微信读书网页版终于能自动阅读了!

微信读书移动端

不知道有多少小伙伴使用微信读书App的? 在移动端有个非常好用的功能叫自动阅读. 这个功能解放了双手, 让阅读更加沉浸式.

image-20240331201916375

微信读书网页端痛点

但是我更喜欢用电脑看书, 电脑版的微信读书就是个网页, 非常的简洁, 除了阅读书籍外没有任何功能. 包括自动阅读. 这就很麻烦了, 这对我来说真的是非常刚需的功能, 没有了自动阅读我都看不下去了, 时不时就要拿鼠标去点一下滚轴. 我想应该不止我一个人遇到了这个问题, 所以先搜索了下浏览器插件.

image-20240404235527906

很遗憾, 看起来也就第一个用的人多点. 但是看起来都不包含自动阅读的能力. 看样子只能自己写一个了.

原谅我词穷, 我真想不到该起什么名字...就和他们同名也无妨, 反正我只想解决我自己的需求.

设计思路

结合日常阅读的习惯, 我设计了以下几个功能点.

  • 开启/关闭自动阅读
  • 调整自动阅读速度
  • 开启自动阅读时, 有时需要手动让滚轴往上/往下走一些
  • 保存配置, 避免每次都要重新设置

首先我倾向于选择键盘按键来实现这些功能, 因为按下一个按键一定比用手抓到鼠标再点击目标要快的多. 经常玩游戏的同学都很熟悉WASD的键位, 在DNF中, D是向右走, 也就是向前行. 而A则是往回走. 因此, 我设定A是降低阅读速度, D则是增加阅读速度.

image-20240331205054961

那么剩下的W和S则对应了往上和往下滚动一小段距离. 这个需求场景是当我们在阅读时, 可能因为某个片段有些复杂或过于简单, 而导致我们想短暂地调整下阅读进度.

而开启和关闭自动阅读, 则是定在了'x'的键位上. 因为我小时候玩的一款叫彩虹岛的网游就是按X攻击的. 因此X在我印象中充满了战斗气息. 怎么样, 我这套键位设计的很合理吧!

image-20240331205842798

成果展示

自动阅读

正如前面我们所约定的那样, 我们打开一本书进行阅读时, 页面右下角会提示你

image-20240405000623585

只需要按下x, 就会开启自动阅读了. 并且这个速度还是可调的

设置中心

不止是这样哦. 因为我显示器比较大, 我发现页面两侧有很大的空白. 所以我还设置了屏占比的功能

这个功能其实是和另一个微信助手借鉴的. 但是他们设置的有bug. 视频版里有详细介绍.

在进入微信读书的时候, 我的插件会在左上角放一颗七龙珠.

至于为什么是七龙珠...没啥特别的原因. 我真就是需要icon的时候突然想起七龙珠了, 就整了一颗放这. 可以点击这颗龙珠召唤, 不是, 点击打开设置面板.

image-20240405000424062

屏占比

官方默认就是1000px的, 最大可以设置2000px. 在我的大显示器上几乎全屏铺满了. 我拿手机拍摄大家对比下.

image-20240405001845536

image-20240405001851578

勿扰模式

前文展示了在调整速度、切换界面的时候右下角是有toast提示的. 有时候这些额外的元素可能会吸引我们的注意, 而插件的用法非常简单, 并不需要反复提醒. 因此, 在设置中我们可以开启勿扰模式, 世界都会变得安静.

image-20240405002027668

菜单自定义显隐

不知道大家有没有感觉这一排的icon很鸡肋

image-20240405164958820

这些icon常驻在页面中, 但是谁会没事干天天改字号? 谁会亮色和暗色主题来回切换? 在我看来就是影响我沉浸式阅读的存在. 因此我做了2个改动. 第一个改动是将其位置从主体页面中移除, 放在了header区域

image-20240405165143446

其次, 正如我前文所说, 这大部分的icon都用不着. 对我来说, 只有目录这个功能确实偶尔会用到. 因为可能对某些章节不感兴趣, 想跳过去. 所以, 我就对他做了个自定义显隐功能.

image-20240405165330263

image-20240405165355336

怎么样? 是不是更合理一些了?

实现方案

浏览器扩展开发, 我建议使用Plasmo进行开发. 他是一个浏览器扩展开发的解决方案, 允许你使用 React 进行开发, 并提供了HMR、打包等一系列的开箱即用的方案. 官方文档写的非常通俗易懂. 不过你需要先了解基础的浏览器插件开发知识, 如Background、Content Script等.

接下来我们来思考如何实现前文中提到的业务. 这里我想挑几个我觉得值得一聊的内容详细说说.

自动阅读

如何让页面自动阅读呢? 转化成技术的用词就是: 如何让滚轴高度稳定的往下滚动. 这个比较简单, 思路如下

  • 获取到页面的滚轴高度
  • 将滚轴高度设置为基于之前获取到的滚轴高度再+上一定的滚轴高度

但是这里有个技术细节, 假定我们的代码片段如下

// speed 是用户设置的阅读速度
let speed;
function addScrollTop(): void {
  let recordScroll = document.documentElement.scrollTop;
  recordScroll += speed;
  document.documentElement.scrollTop = recordScroll;
}

现在当我们调用addScrollTop时, 就会往下滚动一些距离. 那么请问, 调用一次也就一次, 调用两次也就两次, 如何让他不停的调用自己呢? 可能有同学会想到setInterval, 那现在我们来思考一个场景.

当我在使用微信读书的时候, 突然有人给我发了条电脑微信, 我中断了读书的状态回复微信, 结束后再回来, 请问刚刚的自动阅读是不是始终在自动阅读? 如果你使用的是定时器, 那么一定是在继续阅读的. 这将导致你必须往回寻找刚刚的阅读进度.

那么我是如何解决这个问题的呢. 我使用的是requestAnimationFrame, 这个API可以让你的显示器窗口不可见时, 暂停自动阅读. 也就是说, 当我读到某个进度而划走窗口做别的事情时, 再回来, 进度可以无缝衔接. 那么什么叫显示器窗口不可见呢?

image-20240331213523412

其实就是几个桌面窗口的切换. 但是如果我的浏览器和微信都在同一个窗口下, 那么我点击微信, 也就是浏览器失焦的时候, 会停止自动阅读吗? 答案是不会的. 这符合用户习惯, 因为我无法判断用户失焦时是不是期望停止自动阅读. 毕竟阅读时顺手回几句简短的消息也是很正常的操作. 但是切换窗口则通常是有更复杂的任务要执行, 短时间回不来.

判断翻页

之前在完成初版的时候出现了一个bug, 当我阅读完一整页的内容时, 进行翻页. 注意, 翻页是需要手动操作的. 按下右方向键就可以了, 这是官方提供的. 在翻页后, 阅读进度会闪现到很后面. 我们不难分析表现可以推测出, 问题的原因是第一页结束的时候, 滚轴当前的位置比如是800, 翻页后从0开始看. 但因为代码中记得刚刚是看到了800的高度, 所以下一个渲染时间点就把进度调整到了800+speed的位置. 因此, 我们需要在翻页时重置记忆的滚轴高度. 那么怎么判断翻页了呢? 通过对页面的研发不难发现, 当章节变化的时候, 页面上会显示章节的标题.

image-20240331214714087

那么我们只需要监听这个章节的DOM内容变化即可. 我们需要借助MutationObserver的API

const chapterTitle = document.querySelector('.readerTopBar_title_chapter');
const documentObserver = new MutationObserver(function () {
	// 重置滚轴高度
});
// 对章节标题 DOM 进行监听
documentObserver.observe(chapterTitle, {
  attributes: true,
  childList: true,
  characterData: true,
  subtree: true,
});

保存频率过高导致报错

自动阅读的速度、屏占比等都是自动保存的. 每次更改阅读速度, 都会直接保存在浏览器当中.

// 每次需要保存配置的时候就调用该方法
function updateConfig(config) {
  // storage 是 Plasmo 提供的存储模块
  storage.set('config', config);
}

那假如我连续几十次调整速度, 这个函数就被调用了几十次, 然后控制台就报错了.

This request exceeds the MAX_WRITE_OPERATIONS_PER_MINUTE quota

查了下资料, 大概意思是说浏览器不允许插件在短时间内大量的执行存储操作. 那么显然我们就需要上防抖了. 为此我借助了Rxjs中的防抖操作符, 玩Angular的同学应该很熟悉.

const updateConfig$ = new Subject<Config>();
// 更新操作任你调, 我只执行最后一次.
updateConfig$.pipe(debounceTime(500)).subscribe((config: Config) => {
  storage.set('config', config);
});

function updateConfig(config) {
  updateConfig$.next(config);
}

源码中我最终移除了这个方案, 因为只因为这一个场景引入一个lib感觉不太优雅. 我手动用定时器来解决这个问题. 反正目的都是一样的, 能实现防抖就可以.

结语

这个插件只是为了方便我自己使用微信读书. 如果你也需要微信读书, 快来体验沉浸式阅读吧! 目前已上架下列应用商店, 项目地址: https://github.com/Eve-Sama/weread-web-extension


我是前夕, 专注于前端和成长, 希望我的内容可以帮助到你. 公众号: 前夕小课堂

image-20240403101717261

本文禁止转载!

posted @ 2024-04-08 15:02  前夕Sama  阅读(402)  评论(0编辑  收藏  举报