您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
两侧中部 ▲/▼ 按钮,点击瞬时跳转 80% 视口高度,无滚动动画,适合类 Eink 翻页阅读。
// ==UserScript== // @name Eink-style Page Turn Buttons (Instant, 80%, Side-Centered) // @name:zh-CN 类Eink整页翻按钮(瞬时、80%、侧边居中) // @namespace https://example.com/userscripts/pageturn // @version 0.5.1 // @description Two side-centered ▲/▼ buttons for instant 80%-viewport page jumps without animation. // @description:zh-CN 两侧中部 ▲/▼ 按钮,点击瞬时跳转 80% 视口高度,无滚动动画,适合类 Eink 翻页阅读。 // @match *://*/* // @run-at document-end // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; if (window.top !== window.self) return; const cfg = { btnSize: 48, btnOffset: 16, btnGap: 12, pageRatio: 0.8, theme: 'dark', // 'dark' | 'light' bgAlpha: 0.18, btnOpacity: 0.38, leftId: 'ptb-side-left', rightId: 'ptb-side-right' }; // force no smooth scrolling const style = document.createElement('style'); style.textContent = 'html{scroll-behavior:auto!important}'; document.documentElement.appendChild(style); const scroller = document.scrollingElement || document.documentElement; const jumpByRatio = (dir) => { const delta = Math.round(window.innerHeight * cfg.pageRatio); scroller.scrollTop = scroller.scrollTop + dir * delta; }; const mkButton = (label, dir) => { const btn = document.createElement('button'); btn.textContent = label; Object.assign(btn.style, { width: cfg.btnSize + 'px', height: cfg.btnSize + 'px', borderRadius: '50%', border: 'none', cursor: 'pointer', fontSize: '18px', lineHeight: cfg.btnSize + 'px', textAlign: 'center', boxShadow: '0 2px 8px rgba(0,0,0,0.25)', opacity: String(cfg.btnOpacity) }); if (cfg.theme === 'dark') { btn.style.background = `rgb(0 0 0 / ${cfg.bgAlpha})`; btn.style.color = '#fff'; } else { const alpha = Math.min(0.9, Math.max(0.15, 0.6 + cfg.bgAlpha)); btn.style.background = `rgb(255 255 255 / ${alpha})`; btn.style.color = '#000'; btn.style.border = '1px solid rgba(0,0,0,0.15)'; } btn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); jumpByRatio(dir); }); return btn; }; const mkSideGroup = (side, id) => { const wrap = document.createElement('div'); wrap.id = id; Object.assign(wrap.style, { position: 'fixed', top: '50%', transform: 'translateY(-50%)', zIndex: '2147483647', display: 'flex', flexDirection: 'column', alignItems: 'center', gap: cfg.btnGap + 'px', pointerEvents: 'auto' }); wrap.style[side] = cfg.btnOffset + 'px'; wrap.appendChild(mkButton('▲', -1)); wrap.appendChild(mkButton('▼', +1)); (document.body || document.documentElement).appendChild(wrap); }; const ensureUI = () => { if (!document.getElementById(cfg.leftId)) mkSideGroup('left', cfg.leftId); if (!document.getElementById(cfg.rightId)) mkSideGroup('right', cfg.rightId); }; ensureUI(); const observer = new MutationObserver(() => ensureUI()); observer.observe(document.documentElement, { childList: true, subtree: true }); })();