墨水屏电纸书划动优化

消除划动动画 可设置划动倍率和更新间隔

目前為 2025-10-05 提交的版本,檢視 最新版本

// ==UserScript==
// @name         墨水屏电纸书划动优化
// @namespace    http://tampermonkey.net/
// @version      1.10
// @description  消除划动动画  可设置划动倍率和更新间隔
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @run-at       document-start
// @license      MIT
// @author       cxuan.cc
// ==/UserScript==
(function(){
    // 设置项
    let N = GM_getValue('multiplier', 2);
    let intervalSec = GM_getValue('interval', 0);
    GM_registerMenuCommand(`设置滑动倍率(当前 ${N}倍)`, ()=>{
        let v = parseFloat(prompt('输入滑动倍率:', N));
        if(!isNaN(v)) GM_setValue('multiplier', N = v);
    });
    GM_registerMenuCommand(`设置更新间隔(当前 ${intervalSec}秒)`, ()=>{
        let v = parseFloat(prompt('输入更新间隔(秒,0=仅松手时刷新):', intervalSec));
        if(!isNaN(v)) GM_setValue('interval', intervalSec = v);
    });

    const touchMap = {}; // { id: {sy, cy, el, lastDy} }
    let timerId = null;

    function periodicUpdate() {
        for (let id in touchMap) {
            const info = touchMap[id];
            if (info.cy == null) continue;
            let totalDy = (info.sy - info.cy) * N;
            let delta = totalDy - (info.lastDy || 0);
            if (delta) {
                info.el.scrollTop += delta;
                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=>{
        for (const t of e.changedTouches) {
            let el = t.target;
            while (el && el!==document && !(el.scrollHeight>el.clientHeight && /auto|scroll/.test(getComputedStyle(el).overflowY))) {
                el = el.parentNode;
            }
            if (el===document) el = document.scrollingElement||document.documentElement;
            touchMap[t.identifier] = { sy: t.clientY, cy: t.clientY, el, lastDy: 0 };
        }
        startTimer();
    }, { passive:false });

    document.addEventListener('touchmove', e=>{
        let doPrevent = false;
        for (const t of e.changedTouches) {
            const info = touchMap[t.identifier];
            if (!info) continue;
            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) {
        for (const t of e.changedTouches) {
            const info = touchMap[t.identifier];
            if (!info) continue;
            if (intervalSec === 0) {
                // 仅松手时一次性滚动
                let dy = (info.sy - t.clientY) * N;
                info.el.scrollTop += dy;
            } else {
                // 结束时再跑一次增量
                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 });

})();