鸿蒙学习实战之路-Reader Kit获取目录列表最佳实践
最近好多朋友问我:“西兰花啊,我用Reader Kit做了个阅读器,能显示书籍信息了,可怎么才能显示目录让用户跳转章节啊?” 害,这问题可问对人了!咱们做阅读器,目录功能就像地图一样重要,没有它用户就像在迷宫里瞎转~今天这篇,我就手把手带你用Reader Kit获取目录列表,教你怎么显示目录并实现章节跳转,全程不超过10分钟(不含下载时间)~
鸿蒙学习实战之路-Reader Kit获取目录列表最佳实践
最近好多朋友问我:“西兰花啊,我用Reader Kit做了个阅读器,能显示书籍信息了,可怎么才能显示目录让用户跳转章节啊?” 害,这问题可问对人了!咱们做阅读器,目录功能就像地图一样重要,没有它用户就像在迷宫里瞎转~
今天这篇,我就手把手带你用Reader Kit获取目录列表,教你怎么显示目录并实现章节跳转,全程不超过10分钟(不含下载时间)~
一、获取目录列表的基本流程
咱们先来看个流程图,了解一下整个过程是咋回事:

简单来说,整个流程就像咱们看地图找路:
- 先初始化书籍解析器(就像打开地图)
- 获取目录列表(就像查看地图上的各个地点)
- 展示目录(就像把地图摊开给用户看)
- 用户点击目录,获取跳转信息(就像找到目的地的路线)
- 跳转到指定章节(就像按照路线到达目的地)
二、需要用到的接口
咱们做这个功能,主要需要用到4个接口,就像旅行需要用到地图、指南针、导航仪一样:
| 接口名 | 描述 |
|---|---|
| getDefaultHandler | 获取书籍默认解析器,相当于打开地图的工具 |
| getCatalogList | 获取书籍目录列表,相当于地图上的各个地点标记 |
| getDomPosByCatalogHref | 获取阅读起始位置domPos,相当于目的地的具体坐标 |
| getSpineList | 获取书脊内容列表,相当于地图上的主要道路 |
三、具体实现步骤
1. 导入相关模块
首先,咱们得把需要的模块导入进来,就像旅行前先把所有装备都收拾好一样:
import { common } from "@kit.AbilityKit";
import { bookParser } from "@kit.ReaderKit";
import { hilog } from "@kit.PerformanceAnalysisKit";
2. 初始化书籍解析器
接下来,咱们需要初始化书籍解析器,就像旅行前先打开地图确认位置一样:
private defaultHandler: bookParser.BookParserHandler | null = null;
aboutToAppear(): void {
this.init().then(() => {
});
}
private async init() {
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let path: string = `${context.filesDir}/abc.epub`; // 这里的路径是书籍在沙箱中的位置
try {
this.defaultHandler = await bookParser.getDefaultHandler(path);
} catch (error) {
hilog.error(0x0000, "testTAG", `getDefaultHandler failed, Code: ${error.code}, message: ${error.message}`);
}
}
3. 获取并展示目录列表
现在,咱们就可以获取目录列表并展示出来了,就像把地图摊开给用户看一样:
@State catalogItemList: bookParser.CatalogItem[] = [];
aboutToAppear(): void {
this.init().then(() => {
this.getCatalogList();
});
}
private getCatalogList() {
try {
this.catalogItemList = this.defaultHandler?.getCatalogList() || [];
} catch (error) {
hilog.error(0x0000, "testTAG", `getCatalogList failed, Code: ${error.code}, message: ${error.message}`);
}
}
build() {
Column() {
List() {
ForEach(this.catalogItemList, (item: bookParser.CatalogItem) => {
ListItem() {
Column() {
Row() {
Row() {
Text(' · ')
.fontSize(14)
Text(item.catalogName)
.fontSize(14)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.padding({ top: 8, bottom: 8 })
.maxLines(2)
.layoutWeight(1)
}
}
.width('100%')
.height(48)
.justifyContent(FlexAlign.Center)
.alignItems(VerticalAlign.Center)
Divider()
}
.padding({
left: item.catalogLevel ? item.catalogLevel * 26 : 10,
right: item.catalogLevel ? item.catalogLevel * 26 : 10,
top: 6,
bottom: 6
})
.onClick(async () => {
// 点击目录跳转到指定章节
this.jumpToCatalogItem(item);
})
}
})
}
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
}
4. 实现章节跳转功能
最后,咱们需要实现章节跳转功能,就像按照地图上的路线到达目的地一样:
private jumpToCatalogItem(catalogItem: bookParser.CatalogItem) {
let domPos = this.getDomPos(catalogItem);
let resourceIndex = this.getResourceItemByCatalog(catalogItem).index;
// 通过domPos及resourceIndex信息,即可通过startPlay接口跳转到指定位置
hilog.info(0x0000, "testTAG", `jumpToCatalogItem domPos: ${domPos}, resourceIndex: ${resourceIndex}`);
}
private getDomPos(catalogItem: bookParser.CatalogItem): string {
try {
let domPos: string = this.defaultHandler?.getDomPosByCatalogHref(catalogItem.href || '') || '';
return domPos;
} catch (error) {
hilog.error(0x0000, "testTAG", `getDomPos failed, Code: ${error.code}, message: ${error.message}`);
}
return '';
}
/**
* 获取书籍目录对应的资源条目
*
* @param catalogItem 目录条目
*/
private getResourceItemByCatalog(catalogItem: bookParser.CatalogItem): bookParser.SpineItem {
let resourceFile = catalogItem.resourceFile || '';
try {
let spineList: bookParser.SpineItem[] = this.defaultHandler?.getSpineList() || []
// 查找目录对应的资源条目
let resourceItemArr = spineList.filter(item => item.href === resourceFile);
if (resourceItemArr.length > 0) {
hilog.info(0x0000, 'testTag', 'getResourceItemByCatalog get resource ', resourceItemArr[0]);
let resourceItem = resourceItemArr[0];
return resourceItem;
} else if (spineList.length > 0) {
// 如果查找不到,则默认返回第1个资源条目
hilog.info(0x0000, 'testTag', 'getResourceItemByCatalog get resource in resourceList', spineList[0]);
return spineList[0];
}
} catch (error) {
hilog.error(0x0000, "testTAG", `getDomPos failed, Code: ${error.code}, message: ${error.message}`);
}
// 如果没有资源条目,则返回默认值
hilog.info(0x0000, 'testTag', 'getResourceItemByCatalog get resource in escape');
return {
idRef: '',
index: 0,
href: '',
properties: ''
};
}
四、需要注意的地方
🥦 西兰花警告
-
书籍文件必须在沙箱目录:Reader Kit只能读取应用沙箱目录下的书籍文件,就像地图只能在特定区域使用一样,出了范围就不管用了~
-
要处理异常情况:不同格式的电子书可能会有不同的问题,比如有些书籍可能没有目录,咱们得做好异常捕获,就像旅行时要准备好应对突发情况一样~
-
目录层级的处理:代码中通过
item.catalogLevel来设置缩进,这样可以让目录显示出层级关系,就像地图上的道路一样有主次之分~
🥦 西兰花小贴士
-
跳转的小技巧:获取到
domPos和resourceIndex后,咱们可以用ReadPageComponent的startPlay接口来实现跳转,就像导航仪告诉咱们具体怎么走一样~ -
支持的格式:Reader Kit支持txt、epub、mobi、azw、azw3格式的电子书,不过不同格式的目录结构可能会有差异,咱们在开发时要多测试几种格式~
五、下一步行动
现在咱们已经学会了如何获取目录列表并实现章节跳转,接下来可以试试:
- 实现更美观的目录界面,比如添加折叠/展开功能
- 实现阅读进度同步,让目录显示当前阅读位置
- 实现目录搜索功能,让用户可以快速找到想看的章节
📚 推荐资料
我是盐焗西兰花,
不教理论,只给你能跑的代码和避坑指南。
下期见!🥦
更多推荐


所有评论(0)