Greasy Fork is available in English.
回归初心,最简单的样式。右下角固定一个小按钮开关,也可以用 Alt+M。
// ==UserScript==
// @name 小说阅读器 (极简稳定版)
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 回归初心,最简单的样式。右下角固定一个小按钮开关,也可以用 Alt+M。
// @author Gemini
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_xmlhttpRequest
// @connect *
// ==/UserScript==
(function() {
'use strict';
// 防止在 iframe 中无限嵌套
if (window.top !== window.self) return;
// --- 1. 创建一个永远可见的实体开关按钮 ---
const toggleBtn = document.createElement('button');
toggleBtn.textContent = '📚';
toggleBtn.title = '打开/关闭阅读器';
toggleBtn.style.cssText = `
position: fixed;
bottom: 20px;
right: 20px;
z-index: 2147483647;
padding: 5px 10px;
cursor: pointer;
border: 1px solid #ccc;
background: white;
border-radius: 4px;
opacity: 0.6;
font-size: 16px;
`;
document.body.appendChild(toggleBtn);
// --- 2. 创建最简单的主容器 ---
const container = document.createElement('div');
container.style.cssText = `
position: fixed;
bottom: 60px;
right: 20px;
width: 350px;
height: 500px;
background: white;
border: 1px solid #ccc;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 2147483647;
display: none; /* 默认隐藏 */
flex-direction: column;
resize: both;
overflow: hidden;
opacity: 0.85;
font-family: sans-serif;
`;
document.body.appendChild(container);
// --- 3. 顶部控制栏 (只保留输入框、按钮和透明度滑块) ---
const header = document.createElement('div');
header.style.cssText = 'padding: 6px; background: #f8f9fa; border-bottom: 1px solid #ddd; display: flex; gap: 5px; align-items: center;';
const urlInput = document.createElement('input');
urlInput.placeholder = '输入网址...';
urlInput.style.cssText = 'flex-grow: 1; padding: 4px; font-size: 12px; border: 1px solid #ccc;';
urlInput.value = GM_getValue('moyu_last_url', '');
const loadBtn = document.createElement('button');
loadBtn.textContent = '加载';
loadBtn.style.cssText = 'padding: 4px 8px; font-size: 12px; cursor: pointer; background: white; border: 1px solid #ccc;';
const opacityInput = document.createElement('input');
opacityInput.type = 'range'; opacityInput.min = '0.1'; opacityInput.max = '1'; opacityInput.step = '0.05'; opacityInput.value = '0.85';
opacityInput.style.cssText = 'width: 60px; cursor: pointer;';
header.appendChild(urlInput);
header.appendChild(loadBtn);
header.appendChild(opacityInput);
// --- 4. 内容区 ---
const iframe = document.createElement('iframe');
iframe.style.cssText = 'width: 100%; flex-grow: 1; border: none; background: #fff;';
container.appendChild(header);
container.appendChild(iframe);
// --- 5. 核心加载逻辑 ---
const loadUrl = () => {
let url = urlInput.value.trim();
if (!url) return;
if (!url.startsWith('http')) url = 'https://' + url;
loadBtn.textContent = '...';
GM_xmlhttpRequest({
method: "GET",
url: url,
headers: { "User-Agent": navigator.userAgent, "Referer": new URL(url).origin + "/" },
onload: (res) => {
loadBtn.textContent = '加载';
if(res.status !== 200) { iframe.srcdoc = `<div style="padding:20px;color:red;">加载失败,状态码: ${res.status}</div>`; return; }
let html = res.responseText;
const baseTag = `<base href="${url}">`;
const script = `<script>document.addEventListener('click', e => { let a = e.target.closest('a'); if(a && a.href && !a.href.startsWith('javascript:')) { e.preventDefault(); window.parent.postMessage({type:'NAV', url:a.href}, '*'); } });</script>`;
if(html.includes('<head>')) {
html = html.replace('<head>', `<head>${baseTag}`);
} else {
html = baseTag + html;
}
iframe.srcdoc = html + script;
GM_setValue('moyu_last_url', url);
},
onerror: () => { loadBtn.textContent = '加载'; iframe.srcdoc = '<div style="padding:20px;color:red;">网络请求失败</div>'; }
});
};
// --- 6. 事件绑定 ---
loadBtn.onclick = loadUrl;
urlInput.onkeypress = (e) => { if(e.key === 'Enter') loadUrl(); };
// 透明度实时调节
opacityInput.oninput = (e) => { container.style.opacity = e.target.value; };
// 拦截内部跳转
window.addEventListener('message', (e) => {
if(e.data && e.data.type === 'NAV') { urlInput.value = e.data.url; loadUrl(); }
});
// --- 7. 开关逻辑 ---
const toggle = () => {
container.style.display = container.style.display === 'none' ? 'flex' : 'none';
if(container.style.display === 'flex' && urlInput.value && !iframe.srcdoc) loadUrl();
};
// 按钮点击开关
toggleBtn.onclick = toggle;
// 快捷键开关 (Alt+M 作为辅助)
document.addEventListener('keydown', (e) => {
if (e.altKey && e.key.toLowerCase() === 'm') toggle();
});
})();