耗时三个月,我高仿了一个起点小说阅读器
前言
起因是最近看小说的APP广告越来越多,但不少书源内容也时常出现问题。正好摆烂太久让我很有负罪感,就想着趁着这个契机学点新的东西。公司里用的都是vue技术栈,所以我想着用vue3做个小项目,顺便熟悉一下vue3的语法。从八月开始,断断续续搞了点Demo,直到年底稍微有点空闲,才开始着手把整个项目完善起来。
项目地址
github
gitee
支持平台
平台 | 是否支持 |
---|---|
H5 | 是 |
Android | 是 |
IOS | 是 |
小程序 | 需要修改renderjs |
项目介绍
eReader 是一款基于 uni-app 开发的小说阅读器,功能完善,使用便捷,支持跨平台部署。移动端完全由前端实现,无需后端支持,打包后即为一个独立的APP,极大降低了部署和维护成本。H5端由于跨域问题需要启用一个简单的后端服务器,但移动端打包后完全开箱即用。
技术架构与部署
- uni-app 的跨平台特性使得该项目在移动端和H5端之间无缝切换,移动端是纯前端实现,不依赖额外的服务器。
- H5端需要启用后端服务器来解决跨域问题,但移动端完全是前端应用,避免了额外的服务器负担,极大简化了部署和维护流程。
- 使用技术栈如下
- Vue3 + TypeScript:项目基于Vue3和TypeScript实现。
- Node + Express:H5端使用Node + Express搭建了一个简单的后台,负责爬取数据。
- uni.request:在APP端通过uni.request获取数据,不用启用后端应用。
- Cheerio:用Cheerio来解析HTML,提取书籍信息。
- uni.setStorage:数据缓存使用了uni.setStorage存储。
- 阅读引擎:主要是用 canvas.measureText 来计算文本宽度,通过JS计算宽高分页,支持两端对齐、标点避头等排版优化。
- 分页:分页计算用了uni-app的 renderjs 操作Canvas, uni.createCanvasContext 在APP端性能表现不佳,应尽量避免使用。
- 海报分享:海报分享功能使用了 limeui-painter 。
平台功能
- 丰富的书源:内置多个书源,满足大多数阅读需求,并支持灵活切换。
- 全面的功能:包括书架管理、小说搜索、阅读器设置(夜间模式、字体、背景主题、翻页方式)、章节缓存等,功能齐全。
- 个性化体验:支持书签、目录跳转、缓存、夜间模式等用户自定义设置。
- 逻辑闭环:书源管理、阅读设置、书签等功能平滑切换,确保使用流畅、体验一致。
- 详细功能列表
- 书架:可以加入/移除书架、置顶小说、分享(APP端)、查看详情、搜索、小说排序和浏览历史等功能。
- 分组:可以管理小说分组,支持新增、删除、修改、置顶等操作。
- 精选推荐:集成了 夸克热搜 的书单推荐,帮助大家发现热门书籍。
- 我的:包括书源管理、浏览历史、夜间模式、关于、意见反馈、缓存清除和分享等设置。
- 小说搜索:内置了 12 个书源,基本能满足大部分人的阅读需求。
- 书籍详情:展示书籍信息、简介、目录等,支持分享功能。
- 阅读器:支持添加/移除书架、添加/删除书签、查看目录、白天/夜间模式切换、翻页方式、字号和背景主题切换等多项个性化设置。此外,还支持其余书源切换和章节缓存(包括缓存全部、缓存后20章和缓存当前章节后的所有章节)。
- 目录:支持目录查看、缓存状态、书签、章节跳转、快速跳转(比如去当前章节、去底部)等功能。
项目结构
|-- undefined
|-- .prettierignore
|-- .prettierrc.js
|-- index.html
|-- package.json
|-- tsconfig.json
|-- vite.config.ts
|-- src
|-- App.vue
|-- env.d.ts
|-- main.ts
|-- manifest.json
|-- pages.json
|-- type.d.ts
|-- uni.scss
|-- api #请求接口
| |-- common.ts
|-- components
| |-- BookTip.vue #阅读页第一次打开提示
| |-- Expand.vue #书籍详情简介收起与展开
| |-- share.vue #分享组件
| |-- TabBar.vue #重写tabbar,没使用uni自带tabbar
| |-- global #全局组件
| | |-- g-confirm.vue #确认和输入弹窗
| | |-- g-icon-fonts.vue #图标
| | |-- g-page.vue #每个页面根元素,主要是做主题切换,设置全局css样式(uniapp的APP.vue没有根元素)
| | |-- g-popup.vue #底部和中间弹窗封装
| | |-- g-statusbar.vue #顶部statusbar占位组件,h5端高度为0,app端有默认高度
| |-- painter #海报绘制组件
| |-- popover #书架排序气泡窗
|-- directives #vLongPress指令封装
| |-- index.ts
|-- pages
| |-- blank #我的-跳转页面
| | |-- about.vue #关于我们
| | |-- agreement.vue #用户协议
| | |-- feedback.vue #意见反馈
| | |-- history.vue #浏览历史
| | |-- origin.vue #书源管理
| | |-- policy.vue #隐私政策
| |-- bookDetail #书籍详情页
| |-- catalogs #目录页
| |-- groupDetail #分组详情页
| |-- reader #阅读器
| | |-- index.vue
| | |-- index_v1.vue #第一版,使用columns布局分页
| | |-- index_v2.vue #第二版,使用canvas.measureText计算宽度,js计算宽高进行分页(算法不完善,可以看看思路)
| | |-- readerLayout.ts #第三版,感谢 [@前端一锅煮] 大佬的分享
| | |-- components
| | |-- Origin.vue #换源组件
| | |-- Renderjs.vue #使用uniapp的rendejs获取 document 文档对象
| | |-- Renderjs_v2.vue #第二版renderjs
| |-- search #搜索页
| |-- tabBar #自定义tabbar
| |-- book.vue #精选
| |-- home.vue #书架
| |-- personal.vue #我的
| |-- components
| |-- addGr0up.vue #书架、分组详情里[移至分组]功能
| |-- bookDetail.vue #书架、分组详情里长按展示详情功能
| |-- groupItem.vue #分组项
|-- parser #app端数据解析
| |-- catalog.ts #目录解析
| |-- content.ts #章节内容解析
| |-- index.ts
| |-- search.ts #搜索内容解析
| |-- source.ts #内置书源
| |-- top.ts #精选内容解析
|-- static
|-- store #store
| |-- AppOption.ts #app的系统信息
| |-- index.ts #一些缓存相关数据处理:书架、历史、缓存章节、搜索历史等
|-- styles
|-- types
|-- utils
|-- Config.ts
|-- Control.ts
|-- index.ts
|-- request.ts #请求处理和响应拦截
|-- RequestHeader.ts #最初是想伪造请求头的,但是uni的app端ua固定了
后续功能优化
- 错误处理:当前未处理极端情况下的错误请求,导致产品在特定条件下可能不够健壮,后续会加强异常处理。
- 网络字体支持:项目打包后APK约15MB,内置字体包增大了文件体积,后续会考虑支持网络字体加载以实现更丰富的阅读体验。
- 书源导入与更新:第三方书源存在不稳定性,网站变动可能导致解析错误。后续会考虑支持书源离线导入和在线更新,有助于解决此问题。
- 听书功能:作为干眼症患者,听书功能对我来说还是非常重要的,未来计划加入该功能。
- 去除广告:第三方书源可能包含广告和无关链接,影响阅读体验。后续考虑支持长按选择内容去除,并应用到所有章节,将极大提升阅读质量。
项目展示
h5表现
- 书架
- 精选
- 我的
- 搜索
- 详情
- 阅读器
app端表现(IOS)
Android端未完整测试,可能存在部分兼容问题
- 书架(亮)
- 搜索(亮)
- 书源管理(亮)
- 我的(亮)
- 浏览历史(亮)
- 分组(暗)
- 分组详情(暗)
- 我的(暗)
- 意见反馈(暗)
- 详情(暗)
- 分享
- 阅读器
总结
- 最初只是为了学习新技术栈,项目框架、组件设计没考虑太多。但随着功能的增加,组件复用和方法抽象的需求变得明显,过程中也渐渐感觉到有些力不从心。
- 尽管仍有一些缺漏,但是整体来看来这个项目已经勉强算得上是一个完整的、功能闭环的产品。作为一个人独立完成,自己也算是比较满意了。
- 开发过程中遇到了不少挑战,比如阅读器排版引擎就经历了三次重构,才最终达到了理想效果。那段时间搞得头都要秃了(本来所剩无几的发量越加稀少)。 后续会写写教程,记录下开发过程中遇到的坑。
相关
水了几篇文章,回家过年咯(逃~)
- 从零开始手撸一个阅读器--排版引擎的实现(1)
- 从零开始手撸一个阅读器--书源解析功能的实现(2)
- 从零开始手撸一个阅读器--换源功能的实现(3)
- 从零开始手撸一个阅读器--数据结构与数据缓存(4)
- 从零开始手撸一个阅读器--夜间/白天主题色切换(5)
参考
感谢下面两位大佬的文章
作者:何日
来源:juejin.cn/post/7460023342592901183
来源:juejin.cn/post/7460023342592901183