网页滚滚滚

滚动到顶/底、滚动条-新、记录页面滚动、屏幕常亮和自动滚动

目前為 2025-06-24 提交的版本,檢視 最新版本

// ==UserScript==
// @name        网页滚滚滚
// @namespace   http://tampermonkey.net/
// @version      1.0
// @description  滚动到顶/底、滚动条-新、记录页面滚动、屏幕常亮和自动滚动
// @author       ^o^
// @match        *://*/*
// @grant        GM_registerMenuCommand
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    let w = window, d = document;
    let eScrollBtn = true, eScrollBar = true, eWakeLock = true;
    GM_registerMenuCommand('滚动到顶/底按钮:开/关', toggleScrollBtn);
    GM_registerMenuCommand('透明滚动条:开/关', toggleScrollBar);
    GM_registerMenuCommand('保持屏幕常亮:开/关', toggleWakeLock);

    function toggleScrollBtn() {
        eScrollBtn = !eScrollBtn;
        let b = d.getElementById('scroll-top-btn');
        b && b.remove();
        eScrollBtn && initScrollBtn();
    }

    function toggleScrollBar() {
        eScrollBar = !eScrollBar;
        let s = d.getElementById('theScrollBar');
        s && s.remove();
        eScrollBar && initScrollBar();
    }

    function toggleWakeLock() {
        eWakeLock = !eWakeLock;
        eWakeLock ? requestWL() : (wakeLock && wakeLock.release());
    }

    function initScrollBtn() {
        let b = d.createElement('button');
        b.textContent = '▲';
        b.id = 'scroll-top-btn';
        Object.assign(b.style, {
            position: 'fixed', bottom: '15%', right: '15px', zIndex: 999999,
            width: '35px', height: '35px', borderRadius: '50%', padding: 0,
            background: 'rgba(255,255,255,0.3)', backdropFilter: 'blur(5px)',
            boxShadow: '0 2px 6px rgba(0,0,0,0.2)', display: 'none',
            fontSize: '16px', textAlign: 'center', lineHeight: '35px',
            fontWeight: 'bold', cursor: 'pointer', transition: 'all 0.3s ease'
        });
        d.body.appendChild(b);
        let lastY = w.pageYOffset, t;
        w.addEventListener('scroll', () => {
            b.textContent = w.scrollY > lastY ? '▼' : '▲';
            lastY = w.scrollY;
            b.style.display = w.pageYOffset > 100 ? 'block' : 'none';
            clearTimeout(t);
            t = setTimeout(() => b.style.display = 'none', 2000);
        });
        b.addEventListener('mouseenter', () => {
            b.style.background = 'rgba(255,255,255,0.6)';
            b.style.transform = 'scale(1.1)';
            b.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)';
        });
        b.addEventListener('mouseleave', () => {
            b.style.background = 'rgba(255,255,255,0.3)';
            b.style.transform = 'scale(1)';
            b.style.boxShadow = '0 2px 6px rgba(0,0,0,0.2)';
        });
        b.addEventListener('click', () => w.scrollTo({
            top: b.textContent === '▲' ? 0 : d.documentElement.scrollHeight,
            behavior: 'smooth'
        }));
    }

    function initScrollBar() {
        let s = d.createElement("div");
        s.id = "theScrollBar";
        s.innerHTML = "▲<br>▼";
        Object.assign(s.style, {
            position: 'fixed', top: '-14vw', right: '-10vw', zIndex: 9999999,
            width: '6vw', fontSize: '1.5vw', lineHeight: '5vw', opacity: 0,
            background: 'rgba(255,255,255,0.3)', backdropFilter: 'blur(2px)',
            boxShadow: '0 1px 5px rgba(0,0,0,0.2)', borderRadius: '1vw',
            textAlign: 'center', transition: 'opacity 0.4s, right 0.4s'
        });
        d.body.appendChild(s);
        let h = null, lastTop = null, anim = false;
        function updateBar() {
            let st = w.scrollY;
            if (st !== lastTop) {
                let barTop = (st / h) * (w.innerHeight - s.clientHeight);
                s.style.top = barTop < 0 ? 0 : 
                    barTop + s.clientHeight > w.innerHeight ? 
                    w.innerHeight - s.clientHeight + 'px' : barTop + 'px';
                lastTop = st;
            }
            w.requestAnimationFrame(updateBar);
        }
        w.addEventListener("touchstart", () => {
            if (d.documentElement.scrollHeight <= w.innerHeight * 2) return;
            h = d.documentElement.scrollHeight - w.innerHeight;
            updateBar();
        });
        let startY = null;
        function startScroll(e) {
            e.preventDefault();
            startY = e.changedTouches[0].clientY - parseInt(s.style.top);
        }
        function scrolling(e) {
            e.preventDefault();
            let curY = e.changedTouches[0].clientY;
            let barTop = curY - startY;
            s.style.top = barTop < 0 ? 0 : 
                barTop > w.innerHeight - s.clientHeight ? 
                w.innerHeight - s.clientHeight + 'px' : barTop + 'px';
            w.scrollTo(w.scrollX, (barTop / (w.innerHeight - s.clientHeight)) * h);
        }
        s.addEventListener("touchstart", startScroll, { passive: false });
        s.addEventListener("touchmove", scrolling, { passive: false });
        let t;
        w.addEventListener("scroll", () => {
            clearTimeout(t);
            s.style.right = '2vw';
            s.style.opacity = '0.8';
            t = setTimeout(() => {
                s.style.right = '-10vw';
                s.style.opacity = '0';
            }, 1000);
            if (anim) return;
            let st = w.scrollY, spd = Math.abs(st - lastTop);
            if ((st === 0 || st + w.innerHeight >= d.documentElement.scrollHeight) && spd > 7) {
                anim = true;
                s.style.animation = `bounce-${st === 0 ? 'down' : 'up'} 0.4s`;
                setTimeout(() => {
                    s.style.animation = '';
                    anim = false;
                }, 500);
            }
        });
        let style = d.createElement("style");
        style.textContent = `@keyframes bounce-down{0%{transform:translateY(0)}30%{transform:translateY(10px)}100%{transform:translateY(0)}}@keyframes bounce-up{0%{transform:translateY(0)}30%{transform:translateY(-10px)}100%{transform:translateY(0)}}`;
        d.head.appendChild(style);
    }

    let wakeLock = null;
    async function requestWL() {
        if (!('wakeLock' in navigator)) return;
        try {
            wakeLock = await navigator.wakeLock.request("screen");
        } catch (e) {}
    }
    eWakeLock && requestWL();

    let scrolling = false, interval, speed = 25, pixels = 1;
    function toggleAutoScroll() {
        if (scrolling) {
            scrolling = false;
            clearInterval(interval);
        } else {
            scrolling = true;
            interval = setInterval(() => {
                w.scrollBy(0, pixels);
                if (w.innerHeight + w.scrollY >= d.body.scrollHeight) {
                    w.scrollBy(0, 1);
                }
            }, speed);
        }
    }
    GM_registerMenuCommand('自动滚动:开始/停止', toggleAutoScroll);
    GM_registerMenuCommand('自动滚动:配置参数', () => {
        let s = prompt('滚动间隔(ms):', speed);
        if (s !== null) speed = parseInt(s) || speed;
        let p = prompt('每次滚动像素(px):', pixels);
        if (p !== null) pixels = parseInt(p) || pixels;
    });

    eScrollBtn && initScrollBtn();
    eScrollBar && initScrollBar();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址