网页阅读进度条

在网页顶部显示阅读进度条,估算阅读时间

// ==UserScript==
// @name         网页阅读进度条
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  在网页顶部显示阅读进度条,估算阅读时间
// @author       jiangchh
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const READING_SPEED = 200; // 每分钟阅读字数
    const PROGRESS_COLOR = '#4CAF50'; // 进度条颜色

    // 添加样式
    const style = document.createElement('style');
    style.textContent = `
        #reading-progress-container {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 5px;
            background-color: #f0f0f0;
            z-index: 9999;
        }
        #reading-progress-bar {
            height: 100%;
            width: 0;
            transition: width 0.3s ease;
        }
        #reading-progress-info {
            position: fixed;
            top: 5px;
            right: 10px;
            background-color: rgba(255, 255, 255, 0.8);
            padding: 5px 10px;
            border-radius: 3px;
            font-size: 12px;
            z-index: 9999;
        }
    `;
    document.head.appendChild(style);

    // 创建进度条、信息元素和章节导航
    function createProgressBar() {
        const progressContainer = document.createElement('div');
        progressContainer.id = 'reading-progress-container';

        const progressBar = document.createElement('div');
        progressBar.id = 'reading-progress-bar';
        progressBar.style.backgroundColor = PROGRESS_COLOR;

        const progressInfo = document.createElement('div');
        progressInfo.id = 'reading-progress-info';

        progressContainer.appendChild(progressBar);
        progressContainer.appendChild(progressInfo);
        document.body.appendChild(progressContainer);
    }

    // 估算阅读时间
    function estimateReadingTime() {
        const text = document.body.innerText;
        const wordCount = text.trim().split(/\s+/).length;
        const imageCount = document.getElementsByTagName('img').length;
        const videoCount = document.getElementsByTagName('video').length;

        const readingTime = wordCount / READING_SPEED + (imageCount * 10 / 60) + (videoCount * 2);
        return Math.ceil(readingTime);
    }

    let startTime = null;
    let actualReadingTime = 0;

    // 更新进度条和信息
    function updateProgress() {
        const windowHeight = window.innerHeight;
        const documentHeight = document.documentElement.scrollHeight;
        const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
        const scrollPercentage = (scrollTop / (documentHeight - windowHeight)) * 100;

        const progressBar = document.getElementById('reading-progress-bar');
        progressBar.style.width = scrollPercentage + '%';

        const totalMinutes = estimateReadingTime();

        const progressInfo = document.getElementById('reading-progress-info');
        progressInfo.textContent = `已读 ${Math.round(scrollPercentage)}% | 预计阅读时间: ${totalMinutes}分钟 | 实际阅读时间: ${Math.round(actualReadingTime)}分钟`;
    }

    // 初始化
    createProgressBar();
    updateProgress(); // 初始更新
    window.addEventListener('scroll', updateProgress);
    window.addEventListener('resize', updateProgress);

    // 每分钟更新一次实际阅读时间
    setInterval(() => {
        if (startTime === null) {
            startTime = new Date().getTime();
        } else {
            const currentTime = new Date().getTime();
            actualReadingTime += (currentTime - startTime) / 1000 / 60;
            startTime = currentTime;
            updateProgress();
        }
    }, 60000);
})();