Greasy Fork is available in English.
自动滚动页面并具有速度调整功能的油猴插件
将代码全部替换,可实现更密集档位的滚动速度调整。同时,平滑滚动,解放双手。
// ==UserScript==
// @name         自动滚动页面 (极致平滑版)
// @namespace    http://tampermonkey.net/
// @version      0.6
// @description  自动滚动页面,通过将亚像素滚动决策权交给浏览器,实现专业级的极致平滑滚动
// @author       Leeyw & Cjz & Gemini
// @match        *://*/*
// @grant        none
// @license MIT
// @downloadURL https://update.greasyfork.icu/scripts/464795/%E8%87%AA%E5%8A%A8%E6%BB%9A%E5%8A%A8%E9%A1%B5%E9%9D%A2.user.js
// @updateURL https://update.greasyfork.icu/scripts/464795/%E8%87%AA%E5%8A%A8%E6%BB%9A%E5%8A%A8%E9%A1%B5%E9%9D%A2.meta.js
// ==/UserScript==
(function() {
    'use strict';
    let scrolling = false;
    let scrollSpeed = 30; // 默认速度 30 像素/秒
    let deleted = false;
    let targetScrollY = 0; // 记录理想的、带小数的滚动位置
    let lastTimestamp = 0; // 用于存储上一帧的时间戳
    // 自动清除本地存储中的插件配置信息
    localStorage.removeItem('autoScrollEnabled');
    const controlPanel = document.createElement('div');
    controlPanel.style.position = 'fixed';
    controlPanel.style.right = '10px';
    controlPanel.style.bottom = '10px';
    controlPanel.style.zIndex = '1000';
    controlPanel.style.padding = '10px';
    controlPanel.style.backgroundColor = 'rgba(0, 0, 0, 0.6)';
    controlPanel.style.borderRadius = '5px';
    controlPanel.style.color = 'white';
    const speedInput = document.createElement('input');
    speedInput.type = 'number';
    speedInput.step = '1'; // 步长改为 1
    speedInput.value = scrollSpeed;
    speedInput.style.width = '50px';
    const startStopButton = document.createElement('button');
    startStopButton.textContent = '开始';
    const deleteButton = document.createElement('button');
    deleteButton.textContent = '删除';
    controlPanel.appendChild(document.createTextNode('速度 (px/s): '));
    controlPanel.appendChild(speedInput);
    controlPanel.appendChild(document.createElement('br'));
    controlPanel.appendChild(startStopButton);
    controlPanel.appendChild(deleteButton);
    document.body.appendChild(controlPanel);
    startStopButton.addEventListener('click', () => {
        scrolling = !scrolling;
        startStopButton.textContent = scrolling ? '停止' : '开始';
        if (scrolling) {
            lastTimestamp = 0;
            targetScrollY = window.scrollY; // 核心:初始化理想位置为当前位置
            window.requestAnimationFrame(autoScroll);
        }
        // 保存配置信息到本地存储
        saveConfig();
    });
    deleteButton.addEventListener('click', () => {
        // 从本地存储中删除配置信息
        localStorage.removeItem('autoScrollEnabled');
        // 标记插件已被删除
        deleted = true;
        // 从页面中删除插件 UI
        controlPanel.remove();
    });
    speedInput.addEventListener('change', () => {
        scrollSpeed = parseFloat(speedInput.value);
        // 保存配置信息到本地存储
        saveConfig();
    });
    // 【极致平滑版】将亚像素滚动决策权交给浏览器
    function autoScroll(timestamp) {
        if (!scrolling) {
            return;
        }
        if (!lastTimestamp) {
            lastTimestamp = timestamp;
            window.requestAnimationFrame(autoScroll);
            return;
        }
        const deltaTime = (timestamp - lastTimestamp) / 1000;
        lastTimestamp = timestamp;
        // 1. 持续增加理想滚动位置
        targetScrollY += scrollSpeed * deltaTime;
        // 2. 将理想位置直接告诉浏览器,让其自行处理平滑滚动
        window.scrollTo(0, targetScrollY);
        window.requestAnimationFrame(autoScroll);
    }
    // 保存配置信息到本地存储
    const saveConfig = () => {
        localStorage.setItem('autoScrollEnabled', JSON.stringify(scrolling));
    };
    // 如果插件已经被删除,则直接返回,不再执行插件代码
    if (deleted) {
        return;
    }
    // 从本地存储中加载配置信息
    const loadConfig = () => {
        const enabled = JSON.parse(localStorage.getItem('autoScrollEnabled'));
        if (enabled !== null) {
            scrolling = enabled;
        startStopButton.textContent = scrolling ? '停止' : '开始';
        if (scrolling) {
            window.requestAnimationFrame(autoScroll);
        }
    }
};
loadConfig();
})();
👍