阅读记录模块设计
阅读记录
##为提升用户体验,好康漫画网设计了阅读记录(历史记录)模块。
该模块用于记录用户的阅读历史。阅读历史主要记录漫画的id,阅读的当前章节,阅读当前章节的第几页,同时,在页面上可以展示漫画的作者、最新更新章节和漫画的图标。用户可以在匿名时使用本地的阅读历史功能,同时,登陆后要将本地的历史记录和云端记录做一个融合。尽量减少服务器的交互次数。
概述
使用**多端融合算法
**实现漫画的离线和在线阅读记录的同步
需求梳理
- 历史阅读记录模块的主要功能是记录用户阅读漫画的历史。
- 需要记录的信息包括:漫画ID、当前章节、当前章节的页数。
- 页面上需要展示的信息有:漫画作者、最新更新章节、漫画图标。
- 支持匿名用户使用本地阅读历史功能。
- 用户登录后,需要将本地历史记录和云端历史记录进行融合。
- 尽量减少服务器交互次数。
设计实现
- 使用客户端存储技术(如localStorage)存储匿名用户的阅读历史。在用户阅读漫画时,将漫画ID、当前章节、当前章节的页数记录在本地。
- 当用户登录时,从云端获取用户的阅读历史记录。将本地历史记录与云端历史记录进行比较和融合。如果本地记录中存在云端没有的记录,则将其上传到云端。
- 在用户登录状态下阅读漫画时,同时更新本地和云端的阅读历史记录。为了减少服务器交互次数,可以设置一个阅读时间阈值,只有在用户阅读时间超过该阈值时才进行服务器交互,否则仅更新本地记录。
- 在历史阅读记录页面展示漫画作者、最新更新章节、漫画图标等信息。可以通过异步请求获取这些信息,以减少服务器压力。
- 为了优化用户体验,可以在用户查看历史记录时,按照最近阅读时间对漫画进行排序,方便用户快速找到自己想要继续阅读的漫画。
- 提供清除历史记录的功能,以便用户在需要时可以清除本地和云端的历史记录。
- 每次打开漫画详情时,更新本地历史记录存储的漫画图标、更新至等字段。
代码逻辑
- 登录时加载云端数据:当用户登录时,从云端获取他们的阅读历史记录。将这些记录与本地数据合并,仅保留每本漫画的最新记录。将新增或更新的数据同步回云端。
- 更新历史记录:在更新历史记录时,首先检查是否已经存在相同的记录。如果存在相同记录,则使用最新数据更新该记录。如果没有相同记录,则插入一条新记录。
- 删除阅读记录:在删除阅读记录时,从本地记录中删除指定的记录,并同步到云端。
- 本地管理历史记录:使用本地数据来管理历史记录。支持分页查询以便在前端展示。
- 更新漫画详情:每次用户重新进入漫画详情页面时,更新已经存在的漫画记录的详情信息,如章节、图标等。
核心代码
```javascrip
// 登录时合并本地历史记录与云端历史记录
mergeReadingHistoryOnLogin: async function () {
// 获取本地阅读历史记录
this.getLocalReadingHistory();
// 获取云端阅读历史记录
const cloudHistory = await apiUtils.getHistory();
// 合并本地和云端记录 { comicId: '456', chapter: '3', page: '2',comicTitle:'xxx',updateChapter:'xxx',icon:'xxx',author:'xxx' }
const allHistory = [...cloudHistory, ...this.readingHistory.value];
//同一本漫画只保留最新的一条记录
// 通过 comicId 对记录进行分组,并仅保留每组中的最新记录
const groupedHistory = allHistory.reduce((acc, record) => {
if (!acc[record.comicId]) {
acc[record.comicId] = record;
} else if (
parseInt(record.chapter) > parseInt(acc[record.comicId].chapter)
) {
acc[record.comicId] = record;
} else if (
parseInt(record.chapter) === parseInt(acc[record.comicId].chapter) &&
parseInt(record.page) > parseInt(acc[record.comicId].page)
) {
acc[record.comicId] = record;
}
return acc;
}, {});
// 将分组后的记录转换为数组
this.readingHistory.value = Object.values(groupedHistory);
// 保存合并后的记录
this.saveLocalReadingHistory();
// 如果用户已登录,将合并后的记录同步到云端
if (!apiUtils.checkLogin()) {
return;
}
//将新增或者更新的数据同步到云端
// 获取新增的记录
const newRecords = this.readingHistory.value.filter(
(record) => !cloudHistory.some((r) => r.comicId === record.comicId)
);
// 获取更新的记录
const updatedRecords = this.readingHistory.value.filter((record) =>
cloudHistory.some(
(r) =>
r.comicId === record.comicId &&
(parseInt(r.chapter) < parseInt(record.chapter) ||
(parseInt(r.chapter) === parseInt(record.chapter) &&
parseInt(r.page) < parseInt(record.page)))
)
);
// 合并新增和更新的记录
const recordsToSync = [...newRecords, ...updatedRecords];
// 将合并后的记录同步到云端
if (recordsToSync.length > 0) {
await apiUtils.pushHistory({ records: recordsToSync });
}
},
6. │ 用户登录 │
└───────┬───────┘
│
v
┌───────────────┐ ┌─────────────┐
│ 加载云端历史记录 │───────> 合并本地和云端 │
└───────────────┘ └──────┬──────┘
│
v
┌───────────────┐ ┌─────────────┐
│ 同步新增或更新的 │<────── 数据到云端 │
│ 记录 └─────────────┘
└───────────────┘
┌───────────────┐
│ 更新历史记录 │
└───────┬───────┘
│
v
┌───────────────┐
│ 检查是否存在相同 │
│ 记录 │
└───────┬───────┘
│
v
┌───────────────┐ ┌─────────────┐
│ 更新现有记录 │ │ 插入新记录 │
└───────────────┘ └─────────────┘
┌───────────────┐
│ 删除阅读记录 │
└───────┬───────┘
│
v
┌───────────────┐
│ 从本地记录中删除 │
└───────┬───────┘
│
v
┌───────────────┐
│ 同步到云端 │
└───────────────┘
┌───────────────┐
│ 本地管理历史记录 │
└───────┬───────┘
│
v
┌───────────────┐
│ 支持分页查询 │
└───────────────┘
┌───────────────┐
│ 更新漫画详情 │
└───────┬───────┘
│
v
┌───────────────┐
│ 更新历史记录中的 │
│ 漫画详情信息 │
└───────────────┘