让阅读无缝衔接 —— JS 获取用户阅读进度

CKY 于 2022/11/12 在「博客」发布。
标签: #Miracle#博客#JavaScript

很多博客中最常见的问题就是:文章很长,但是读者很忙。下次阅读的时候,可能要花一些时间才能恢复到先前的阅读位置。如果可以设备间,识别二维码或是一个链接就可以让阅读无缝衔接,直接跳转到相应位置,那么阅读体验就会变得更加优秀。那么,开始吧!

前言

很多博客中最常见的问题就是:文章很长,但是读者很忙。下次阅读的时候,可能要花一些时间才能恢复到先前的阅读位置。

如果可以设备间,识别二维码或是一个链接就可以让阅读无缝衔接,直接跳转到相应位置,那么阅读体验就会变得更加优秀。

那么,开始吧!

实践

要知道阅读位置,那么就要知道当前页面的坐标。

const getScrollPosition = (el = window) => ({
    x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
    y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
});
// getScollPosition().x => 页面横坐标; getScrollPosition().y => 页面纵坐标;

大部分情况下,我们只用关注纵坐标。横坐标大概率为 0

我们还需要一个页面滚动的事件,用于记录当前坐标,并储存在临时存储中。

至于为什么是 sessionStorage 而不是 localStorage,则是因为 localStorage 除手动清除外,不会自动过期。

// 此处的 750 是「页面元素的最大宽度」
var wx = window.innerWidth >= 750 ? 750 : window.innerWidth;
var wy = window.innerHeight;
function windowScroll() {
    // 反复修改 确保页面尺寸不改变
    wx = window.innerWidth >= 750 ? 750 : window.innerWidth;
    wy = window.innerHeight;
    let y = Math.round(getScrollPosition().y);
    // 组合字符串,同时记录页面坐标,页面宽度和高度
    let p = `${y}:${wx}:${wy}`;
    // 写入到 sessionStorage 中
    sessionStorage.setItem("read_y", p);
}
window.onscroll = windowScroll;

你可能发现了,此处的变量 p,并不仅仅是「页面纵坐标」,而是「页面高度」与「纵坐标」的组合字符串。

事实上,如果单纯是纵坐标判断位置,那么在不同高度,不同宽度的设备上,就会出现错位的情况。而同时记录三个信息,就可以还原真实坐标。

// URL 中是否包含传递的坐标信息
if (location.hash.split("#read=").length > 1) {
    // 分离字符串
    let read_y = location.hash.split("#read=")[1];
    read_y = read_y.split(":");
    // 组合乘积,顺滑移动至坐标
    window.scrollTo({top: Math.round(Number(read_y[0]) * Number(read_y[1] * Number(read_y[2] / wx / wy))), behavior: "smooth"});
} else {
    // 从 sessionStorage 中获取
    let read_y = sessionStorage.getItem("read_y") || "0:0:0";
    read_y = read_y.split(":");
    window.scrollTo({top: Math.round(Number(read_y[0]) * Number(read_y[1] * Number(read_y[2] / wx / wy))), behavior: "smooth"});
}

到现在,我们已经完成了 URL 的解析和基本生成。

那么,URL 即为:

`${location.protocol}//${location.hostname}${location.port ? ":"+location.port:location.port}${location.pathname}#read=${sessionStorage.getItem("read_y")}`;

最后

搭配生成二维码等插件效果更佳。

Miracle 主题将在下个版本中更新该功能。

由 Google 提供的广告

此广告内容由 Google Ads 提供,与 CKY.IM 无关,请注意识别。为什么会显示广告?