您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
消除划动动画 可设置划动倍率和更新间隔 支持手势缩放和双击复位(整体布局缩放)
当前为
// ==UserScript== // @name 墨水屏电纸书划动优化 // @namespace cc.cxuan.books // @version 1.28 // @description 消除划动动画 可设置划动倍率和更新间隔 支持手势缩放和双击复位(整体布局缩放) // @match *://*/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @run-at document-end // @noframes // @license MIT // ==/UserScript== (function(){ // --- 设置项 --- let mx = GM_getValue('multiplierX', 5), my = GM_getValue('multiplierY', 2), intervalSec = GM_getValue('interval', 0), enableZoom = GM_getValue('enableZoom', 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(`切换双指放大/双击复位(当前 ${enableZoom?'开':'关'})`, ()=>{ GM_setValue('enableZoom', enableZoom=!enableZoom); location.reload(); }); // --- 缩放函数 --- const defaultScale = 1; let currentScale = defaultScale, pinch = null; function applyScale(s){ const html = document.documentElement; html.style.transformOrigin = '0 0'; html.style.transform = 'scale('+s+')'; html.style.width = (100/s)+'vw'; } // --- 滑动逻辑 --- const touchMap = {}; let timerId = null; function periodicUpdate(){ for(let id in touchMap){ let info = touchMap[id]; if(info.cx==null||info.cy==null) continue; let dxTot = (info.sx - info.cx)*mx, dyTot = (info.sy - info.cy)*my, dX = dxTot - (info.lastDx||0), dY = dyTot - (info.lastDy||0); if(dX) info.el.scrollLeft += dX; if(dY) info.el.scrollTop += dY; info.lastDx = dxTot; info.lastDy = dyTot; } } function startTimer(){ if(intervalSec>0 && !timerId) timerId = setInterval(periodicUpdate, intervalSec*1000); } function stopTimer(){ if(timerId){ clearInterval(timerId); timerId = null; } } document.addEventListener('touchstart', e=>{ // 双指缩放 if(enableZoom && e.touches.length===2){ let [t1,t2] = e.touches; pinch = { initialDist: Math.hypot(t2.clientX-t1.clientX, t2.clientY-t1.clientY), initialScale: currentScale }; e.preventDefault(); return; } if(e.touches.length>1) return; for(let t of e.changedTouches){ let el = t.target; while(el && el!==document){ let st = getComputedStyle(el), canY = el.scrollHeight>el.clientHeight && /auto|scroll/.test(st.overflowY), canX = el.scrollWidth>el.clientWidth && /auto|scroll/.test(st.overflowX); if(canY||canX) 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=>{ // pinch 缩放 if(pinch){ let [t1,t2] = e.touches; let dist = Math.hypot(t2.clientX-t1.clientX, t2.clientY-t1.clientY); currentScale = +(pinch.initialScale * dist/pinch.initialDist).toFixed(2); applyScale(currentScale); e.preventDefault(); return; } if(e.touches.length>1) return; let doPrevent = 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)){ doPrevent = true; } } if(doPrevent) e.preventDefault(); }, { passive:false }); function finishTouch(e){ // pinch 结束 if(pinch && e.touches.length<2){ pinch = null; return; } 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, 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) stopTimer(); } document.addEventListener('touchend', finishTouch, { passive:false }); document.addEventListener('touchcancel', finishTouch,{ passive:false }); // 双击复位 let lastTap=0; document.addEventListener('touchend', e=>{ if(!enableZoom) return; if(e.touches.length===0 && e.changedTouches.length===1){ let now = Date.now(); if(now - lastTap < 300){ let de = document.scrollingElement||document.documentElement, lx = de.scrollLeft, ly = de.scrollTop; currentScale = defaultScale; applyScale(currentScale); de.scrollLeft = lx; de.scrollTop = ly; } lastTap = now; } }, { passive:false }); // 页面载入时应用默认缩放 if(enableZoom) applyScale(defaultScale); })();