您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
消除划动动画 可设置划动倍率和更新间隔 可设置双指放大双击复原
当前为
// ==UserScript== // @name 墨水屏电纸书划动优化+双指缩放 // @namespace cc.cxuan.books // @version 1.25 // @description 消除划动动画 可设置划动倍率和更新间隔 可设置双指放大双击复原 // @match *://*/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @run-at document-end // @noframes // @license MIT // @author cxuan.cc // ==/UserScript== (function(){ // --- 强制解除网页原缩放限制 --- let mv = document.querySelector('meta[name=viewport]'); if(mv){ mv.setAttribute('content','width=device-width, initial-scale=1, minimum-scale=0.1, maximum-scale=10, user-scalable=yes'); } else { let m = document.createElement('meta'); m.name='viewport'; m.content='width=device-width, initial-scale=1, minimum-scale=0.1, maximum-scale=10, user-scalable=yes'; document.head.appendChild(m); } // --- 设置项 --- let mx = GM_getValue('multiplierX', 5); let my = GM_getValue('multiplierY', 2); let intervalSec = GM_getValue('interval', 0); let enableDoubleReset = GM_getValue('enableDoubleReset', true); GM_registerMenuCommand(`设置X轴移动倍率(当前 ${mx})`, ()=>{ let v = parseFloat(prompt('X 轴滑动倍率:', mx)); if (!isNaN(v)) { GM_setValue('multiplierX', mx=v); location.reload(); } }); GM_registerMenuCommand(`设置Y轴移动倍率(当前 ${my})`, ()=>{ let v = parseFloat(prompt('Y 轴滑动倍率:', my)); if (!isNaN(v)) { GM_setValue('multiplierY', my=v); location.reload(); } }); GM_registerMenuCommand(`设置更新间隔(当前 ${intervalSec}s)`, ()=>{ let v = parseFloat(prompt('更新间隔(秒,0=仅松手时刷新):', intervalSec)); if (!isNaN(v)) { GM_setValue('interval', intervalSec=v); location.reload(); } }); GM_registerMenuCommand(`切换双击复位(当前 ${enableDoubleReset ? '开' : '关'})`, ()=>{ enableDoubleReset = !enableDoubleReset; GM_setValue('enableDoubleReset', enableDoubleReset); location.reload(); }); // --- 捏合缩放相关 --- let initialZoom = parseFloat(document.body.style.zoom) || 1; let currentZoom = initialZoom; let pinchStartDist = 0; let pinchStartZoom = initialZoom; function getDist(t1, t2){ let dx = t1.clientX - t2.clientX, dy = t1.clientY - t2.clientY; return Math.hypot(dx, dy); } document.addEventListener('touchstart', e=>{ if(e.touches.length===2){ // 开始捏合 pinchStartDist = getDist(e.touches[0], e.touches[1]); pinchStartZoom = currentZoom; } },{passive:false}); document.addEventListener('touchmove', e=>{ if(e.touches.length===2){ // 处理捏合 let d = getDist(e.touches[0], e.touches[1]); let scale = pinchStartZoom * (d / pinchStartDist); currentZoom = scale; document.body.style.zoom = scale; e.preventDefault(); return; } },{passive:false}); // --- 触摸滑动优化 --- const touchMap = {}; let timerId = null; function periodicUpdate(){ for(let id in touchMap){ let info = touchMap[id]; if(info.cx==null) continue; let totalDx = (info.sx - info.cx)*mx; let totalDy = (info.sy - info.cy)*my; let dX = totalDx - (info.lastDx||0); let dY = totalDy - (info.lastDy||0); if(dX) info.el.scrollLeft += dX; if(dY) info.el.scrollTop += dY; info.lastDx = totalDx; info.lastDy = totalDy; } } function startTimer(){ if(intervalSec>0 && !timerId) timerId = setInterval(periodicUpdate, intervalSec*1000); } function stopTimer(){ if(timerId) { clearInterval(timerId); timerId = null; } } document.addEventListener('touchstart', e=>{ if(e.touches.length>1) return; for(let t of e.changedTouches){ let el = t.target; while(el && el!==document){ let st = getComputedStyle(el); if((el.scrollHeight>el.clientHeight && /auto|scroll/.test(st.overflowY)) ||(el.scrollWidth>el.clientWidth && /auto|scroll/.test(st.overflowX))){ break; } el = el.parentNode; } if(!el||el===document){ el = document.scrollingElement||document.documentElement; } touchMap[t.identifier] = { sx:t.clientX, sy:t.clientY, cx:t.clientX, cy:t.clientY, el, lastDx:0, lastDy:0 }; } startTimer(); },{passive:false}); document.addEventListener('touchmove', e=>{ if(e.touches.length>1) return; let prevent=false; for(let t of e.changedTouches){ let info = touchMap[t.identifier]; if(!info) continue; info.cx = t.clientX; info.cy = t.clientY; // 保留下拉刷新 if(!(info.el === (document.scrollingElement||document.documentElement) && info.el.scrollTop===0 && (t.clientY-info.sy)>0)){ prevent = true; } } if(prevent) e.preventDefault(); },{passive:false}); function finishTouch(e){ if(e.touches.length>1) return; for(let t of e.changedTouches){ let info = touchMap[t.identifier]; if(!info) continue; if(intervalSec===0){ let dx=(info.sx - t.clientX)*mx; let dy=(info.sy - t.clientY)*my; info.el.scrollLeft += dx; info.el.scrollTop += dy; } else { info.cx = t.clientX; info.cy = t.clientY; periodicUpdate(); } delete touchMap[t.identifier]; } if(Object.keys(touchMap).length===0) stopTimer(); } document.addEventListener('touchend', finishTouch, {passive:false}); document.addEventListener('touchcancel', finishTouch, {passive:false}); // --- 双击复位到捏合前比例 --- let lastTap = 0; document.addEventListener('touchend', e=>{ if(!enableDoubleReset) return; if(e.touches.length===0 && e.changedTouches.length===1){ let now = Date.now(); if(now - lastTap < 300){ // 恢复到捏合前初始比例 document.body.style.zoom = initialZoom; currentZoom = initialZoom; } lastTap = now; } },{passive:true}); })();