Vue-eBookReader 学习笔记(书签功能、页眉页脚、兼容性优化)
4、书签功能、页眉页脚、兼容性优化
4.1 书签原理
- 功能:当用户在某一页面往下拖动时,整个页面会向下移动,并且显示上面的书签组件,移动距离达到一定阈值时书签组件就固定不动且出现添加书签字样。
- 原理:
- 先在阅读器组件中绑定touchmove和touchend事件,(注意为什么不是touchstart和touchend呢,因为这里要实时计算出当前移动的距离 不是仅仅需要最后和开始的距离)计算出当前离开始移动时的距离后,存到vuex中offsetY里
- 下拉是整个页面下去,所以是index.vue整个根组件下去,是在index.vue中用watch方法监听offsetY的值有没有发生变化,如果这个值大于0就向下直接赋值为top(加上过渡动画)
- 书签分为左右两个部分,左边是图标和文字 右边是书签的形状,这里将左边部分直接写在index.vue中,右边书签形状部分另外写一个BookMark组件(由于可能需要多次使用,写在common文件夹下)
4.2 书签实现
-
下拉
- 第零阶段:当前移动量为0(touchend,手松开的一瞬间),其实就是归位操作,将当前的图标,书签形状的位置都归为最开始的样子
- 第一阶段:绑定touchmove和touchend修改vuex的offsetY,在bookmark组件里将该值赋给样式里的top
- 第二阶段:下拉高度在 第一阶段结束 和到阈值(添加书签)之间时,这时书签顶在上面静止不动,用书签和页面同时移动来实现(但文字和箭头还是像一开始一样)
- 第三阶段:达到添加书签的阈值,文字和箭头都发生变化(这时书签也在上面不动)
-
书签吸顶状态实现:当达到二三阶段时(在EbookBookMark组件内用watch监听offsetY变化),书签盒子和页面一起移动,改变样式即可(注意这里是整个书签页面都要不动,文字和形状),同时还要旋转箭头改变文字颜色什么的
-
书签固定位置:也就是正式添加书签,这里定义了一个变量isFixed来看当前是否是书签,若是则添加相应的fixedStyle样式,若不是就删除,各个阶段根据当前是否已经存在书签(isBookmark)来判断设置isfixed为真还是假;最后到第0阶段 也就是松手的一瞬间,若isfiexed还为真就说明要添加书签,为假就不用
-
添加书签,由于书签是要能够及时查找并且保存的,所以将bookmark数组放到localStorage中存储下来,首先通过epubjs的cfi解析原理获取 当前添加书签处那一页的文本,再将当前start的cfi和文本存入bookmark数组(首次要看是否存在,不存在则要先赋初值[])
-
删除书签,同样也是先获取localStorage里的bookmark数组,通过比较当前页面start的cfi与bookmark数组中的cfi,若不相同则保留,相同则删除,再调用setIsBookmark(false)
-
但像上面这样做完之后,发现添加了一页书签后每一页都会有书签显示,这时因为已经将isBookmark设为真了,而每一次翻页的时候又没有进行当前页是否是书签的判断
- 在refreshLocation里添加当前页是否是书签页的判断(利用es6新加的数组的some方法),来设置当前的isBookmark
- 但这样设置之后还不够,因为只是单纯的设置了,页面还没有对其做出响应,所以在EbookBookmark组件里对isBookmark进行监听,若当前是真则将书签加上,不是则不加
-
展示书签条目:还记得之前有个component动态组件吧(用is绑定组件),切换书签和目录条目的,这里再写一个书签条目组件来切换,内容布局都很简单,和目录差不多,用scroll组件来展示,点击可以切换
4.3 页眉页脚
- 其实就是在页面顶部与底部放两个新的组件,这两个组件是阅读过程中一直存在的
- EbookHeader组件的页眉,放的是当前的章节名称,比较简单,EbookFooter是页脚,放的就是当前的阅读进度,这两个组件都是绝对定位,放到index.vue里
4.4 微信兼容
- 手机端点击屏幕出现闪烁现象:在reset.css中加上:
-webkit-tab-hightlight-color: rgba(0, 0, 0, 0);
即可 - 下拉添加书签的时候 move函数要记得加上preventDefault()
- 在initRendition函数里,加上
method: default
4.5 PC端优化
4.5.1 由于pc端的话必须要自适应布局才可以在不同的宽高下显示正常的比例,所以宽高定死的盒子往往就会有一些小问题
- 在侧边栏的部分,书籍名称以及作者的地方就有些显示不完全,这就是由于宽度已经定死了,所以这里采用flex布局来让页面支持自适应,让外层盒子加上flex布局,里面文字部分是原来的ellipsis2(2),将固定的宽度去掉
4.5.2 鼠标事件优化
在移动端都是通过touch的事件来处理,但pc端是鼠标事件,所以这里还要再添加mouse相关的事件
-
首先要分为四个阶段,定义一个mouseState变量,有四个值含义如下:
- 1、鼠标进入(onMouseEnter):函数内置mouseState为1
- 2、鼠标进入后移动(onMouseMove):移动的时候和touchmove一样的去计算当前的offsetY,一样的去改变vuex中的值去影响其余组件
- 3、鼠标移动后松开(onMouseEnd):松开的时候和touchend一样,还原书签和文字的位置,以及设置firstOffsetY和offsetY为默认值
- 4、鼠标松开后移动(onMaskClick):这个函数本来是处理蒙板点击事件的,所以当鼠标是按下且没有移动才会触发该事件,所以stateMouse是2或3都直接返回,不处理
-
我们只需要处理鼠标按下后移动的状态,其余鼠标的移动不需要考虑
-
另外需要点击消抖,有的时候鼠标按下后有轻微的移动,但是用户需要的还是点击事件,但系统判断的确是移动事件,会跳到状态3,而onMaskClick并不会对状态3的mouseState进行处理,因此这里需要增加一个对点击时间的判断,若点击时间小于某一个特定值,即使有轻微的移动,也算作是点击事件
4.6 分页(具体到每一页)
- 首先在EbookReader组件中的分页完毕后的回调函数里,根据观察locations分出来每一页以及navigations中目录的某部分相同,将属于同一章节的页面放到那一章节的对象下,这样就能统计出每一章有多少页,显示到侧边栏的目录条目中
- 页脚右下角的页面要通过,改造refreshLocation函数来显示,因为每切换一次位置都要改变页码,这里是通过currentLocation.start.location获取当前页码
- 总页数,通过EbookReader中分页完毕后将locations对象存到vuex中的pagelist变量里,后续要获取总页数就是pagelist.length即可
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!