You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于视口与div位置计算文章阅读进度百分比?

博客文章阅读进度百分比计算问题修复

问题场景

我在搭建博客时需要实现**显示访客当前阅读文章深度(百分比)**的功能,通过追踪浏览器底部边界与文章位置对比计算。页面有一个60vh高的顶部横幅(含标题、元数据),文章在横幅下方,无固定高度且未设置overflow: scroll。

当前实现代码如下:

const getScrollPercent = () => {
    const prose = document.querySelector<HTMLDivElement>('.prose')

    if (prose) {
        // closest way I got the actual div's top side)
        const proseTop = prose.getBoundingClientRect().top + document.documentElement.scrollTop
        const proseBottom = proseTop + prose.offsetHeight
        const browserBottom = window.scrollY + window.innerHeight

        if (browserBottom < proseTop) {
            return 0
        } else if (browserBottom > proseTop && browserBottom < proseBottom) {
            return (browserBottom / proseBottom) * 100
        } else {
            return 100
        }
    } else {
        return 0
    }
}

但实际表现存在问题:.prose未进入视口时显示0%符合预期,但刚进入视口第一像素时,百分比直接跳至约24%,滚动到文章底部时能正常显示100%。

补充HTML结构(Nuxt/VueJS环境):

<nav>
<!-- Contains some links-->
</nav>

<main>
  <header>
    <h1>Some article title with a banner in background</h1>
    <div class="meta">
      <!-- Some meta infos (tags, creation date, etc) -->
    </div>
  </header>
  <div class="progress">
    <span class="global">
      {{ getScrollPercent }}%
    </span>
  </div>

  <article>
    <!-- lots of <p> and <h2> to <h6> tags, about 2200px high) !-->
  </article>

</main>

问题原因

核心问题出在进度计算逻辑:当前用browserBottom / proseBottom * 100计算,而proseBottom是从页面顶部到文章底部的总距离,当浏览器底部刚碰到文章顶部时,browserBottom已经等于proseTop(即顶部横幅的高度),此时的比值直接导致百分比跳变。正确的计算应该是浏览器底部进入文章区域的距离,除以文章自身的总高度,才能从0%开始递增。

修复方案

调整计算逻辑,用(browserBottom - proseTop)得到已阅读的文章高度,再除以文章自身高度prose.offsetHeight,最后乘以100得到百分比:

const getScrollPercent = () => {
    const prose = document.querySelector<HTMLDivElement>('.prose')

    if (prose) {
        const proseTop = prose.getBoundingClientRect().top + document.documentElement.scrollTop
        const proseHeight = prose.offsetHeight
        const browserBottom = window.scrollY + window.innerHeight

        if (browserBottom < proseTop) {
            return 0
        } else if (browserBottom > proseTop && browserBottom < proseTop + proseHeight) {
            // 计算已阅读部分占文章总高度的比例
            const scrolledIntoProse = browserBottom - proseTop
            return (scrolledIntoProse / proseHeight) * 100
        } else {
            return 100
        }
    } else {
        return 0
    }
}

额外优化

如果需要处理百分比的小数精度,可以用Math.round()或toFixed()格式化结果,例如:

return Math.round((scrolledIntoProse / proseHeight) * 100)

内容的提问来源于stack exchange,提问作者Jaeger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 15:01:12