Greasy Fork

来自缓存

Greasy Fork is available in English.

阅读位置记忆

自动保存和恢复阅读位置,无任何UI提示,支持移动端特性适配

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         阅读位置记忆
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  自动保存和恢复阅读位置,无任何UI提示,支持移动端特性适配
// @author       You
// @match        *://*/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 生成当前页面的唯一标识 (保留 search 参数以区分分页,去除 hash 防止页内跳转干扰)
    const pageKey = 'read_pos_' + window.location.origin + window.location.pathname + window.location.search;

    // 核心逻辑:恢复阅读位置
    function restorePosition() {
        const savedPos = localStorage.getItem(pageKey);
        if (savedPos !== null) {
            const pos = parseFloat(savedPos);
            if (pos > 0) {
                // 首次尝试滚动
                window.scrollTo(0, pos);
                // 延迟 500ms 再次强制校准,应对移动端图片延迟加载或动态渲染导致的页面高度突变
                setTimeout(() => window.scrollTo(0, pos), 500); 
            }
        }
    }

    // 核心逻辑:防抖保存当前位置
    let scrollTimeout;
    function savePosition() {
        if (scrollTimeout) {
            clearTimeout(scrollTimeout);
        }
        scrollTimeout = setTimeout(() => {
            const currentPos = window.scrollY || document.documentElement.scrollTop;
            localStorage.setItem(pageKey, currentPos);
        }, 500); // 停止滚动 500ms 后才执行存储,节省性能
    }

    // 绑定滚动事件监听(passive: true 提升移动端滚动流畅度)
    window.addEventListener('scroll', savePosition, { passive: true });

    // 页面加载时的执行逻辑
    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        restorePosition();
    } else {
        window.addEventListener('DOMContentLoaded', restorePosition);
        // 保底:确保所有资源加载完毕后再执行一次
        window.addEventListener('load', restorePosition);
    }
})();