# book **Repository Path**: Chennile/book ## Basic Information - **Project Name**: book - **Description**: 基于HarmonyOS 5.0.0(12)开发的小说应用。包括书城,书架,我的,阅读器。持续更新中~ 鸿蒙小说,火炬文学。 - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-01-20 - **Last Updated**: 2026-01-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 火炬文学 鸿蒙小说示例 ### 介绍 基于HarmonyOS 5.0.0(12)开发的小说阅读应用。包括书城,书架,我的,阅读器。持续更新中~ ### 效果图预览 ![](./entry//src/main/resources/rawfile/示例.gif) ### 使用说明 1. DevEco Studio 5.0版本导入项目 2. 选择模拟器运行。 3. 项目所使用的数据均是本地模拟数据 如果需要使用自己服务器的数据,src/utils/Config 中 BASE_URL 修改为服务器域名。 src/api/中User.ets 中getUserInfoApi 为例 配置成对应服务端api即可。 ### 部分工程结构&模块类型说明 ``` src |-- api //api文件夹 | |-- Book.ets | |-- Bookcity.ets | |-- User.ets | |-- bookData | |-- BannerData.ets | |-- BookcityData.ets | |-- BookData.ets | |-- RecordsData.ets |-- commonClass //公用类文件夹 | |-- ComponentRef.ets | |-- SetValueClass.ets | |-- User.ets |-- components //组件文件夹 | |-- NavBar.ets | |-- NoData.ets |-- entryability //入口文件夹 | |-- EntryAbility.ets |-- entrybackupability | |-- EntryBackupAbility.ets |-- pages //页面文件夹 | |-- Login.ets | |-- BookCity | | |-- BookCity.ets | | |-- BookList.ets | |-- BookClass | | |-- BookClass.ets | |-- Index | | |-- Index.ets | |-- My | | |-- about.ets | | |-- bindPhone.ets | | |-- buylog.ets | | |-- My.ets | | |-- policy.ets | | |-- recharge.ets | | |-- rechargelog.ets | | |-- set.ets | | |-- subscribe.ets | |-- Read | | |-- Read.ets | | |-- components | |-- Tabs | |-- Tabs.ets |-- types //类型定义 | |-- Book.ets | |-- bookcity.ets | |-- Data.ets | |-- Index.ets | |-- TabBarItem.ets |-- utils //公用方法 |-- Common.ets |-- Config.ets //配置文件 |-- MyDataSource.ets |-- MyWindow.ets |-- PreferencesUtil.ets |-- Request.ets //请求封装 ``` ### 本例涉及的关键特性和实现方案如下: #### LazyForEach:数据懒加载 实现目录长列表的渲染 源码参考:
[Read.ets](./entry/src/main/ets/pages/Read/Read.ets)
```typescript class BasicDataSource implements IDataSource { private listeners: DataChangeListener[] = []; private originDataArray: T[] = []; public totalCount(): number { return 0; } public getData(index: number): T { return this.originDataArray[index]; } // 该方法为框架侧调用,为LazyForEach组件向其数据源处添加listener监听 registerDataChangeListener(listener: DataChangeListener): void { if (this.listeners.indexOf(listener) < 0) { console.info('add listener'); this.listeners.push(listener); } } // 该方法为框架侧调用,为对应的LazyForEach组件在数据源处去除listener监听 unregisterDataChangeListener(listener: DataChangeListener): void { const pos = this.listeners.indexOf(listener); if (pos >= 0) { console.info('remove listener'); this.listeners.splice(pos, 1); } } // 通知LazyForEach组件需要重载所有子组件 notifyDataReload(): void { this.listeners.forEach(listener => { listener.onDataReloaded(); }) } // 通知LazyForEach组件需要在index对应索引处添加子组件 notifyDataAdd(index: number): void { this.listeners.forEach(listener => { listener.onDataAdd(index); }) } // 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件 notifyDataChange(index: number): void { this.listeners.forEach(listener => { listener.onDataChange(index); }) } // 通知LazyForEach组件需要在index对应索引处删除该子组件 notifyDataDelete(index: number): void { this.listeners.forEach(listener => { listener.onDataDelete(index); }) } } export class MyDataSource extends BasicDataSource { private dataArray: T[] = []; public totalCount(): number { return this.dataArray.length; } public getData(index: number): T { return this.dataArray[index]; } public addData(index: number, data: T): void { this.dataArray.splice(index, 0, data); this.notifyDataAdd(index); } public pushData(data: T): void { this.dataArray.push(data); this.notifyDataAdd(this.dataArray.length - 1); } } // 目录 @Component struct catalog { @ObjectLink BookInfo: BookInfo @Prop CatalogListLength:number @Link showCatalog:boolean CatalogList:CatalogItemI[] = [] data:MyDataSource = new MyDataSource() // 父组件将方法传入子组件。 getRead:Function = (book_id?:number,sort?:number) => { } aboutToAppear(){ console.log(JSON.stringify(this.CatalogList),111) this.CatalogList.forEach((item)=>{ this.data.pushData(new CatalogItem(item)) }) } build() { Column() { Column() { Row() { Image($rawfile(this.BookInfo.cover)).height(80).width(60).borderRadius(5) Column() { Text(this.BookInfo.title).margin({bottom:8}).maxLines(1).textOverflow({overflow:TextOverflow.Ellipsis}).width('80%') Text(this.BookInfo.ctitle.length > 0 ? this.BookInfo.ctitle[0] : '') .fontSize(12) .fontColor($r('app.color.text2')) .margin({bottom:8}) Text(this.BookInfo.description).textOverflow({ overflow: TextOverflow.Ellipsis }).maxLines(2).width('80%') .fontSize(12) .fontColor($r('app.color.text2')) } .padding({left:10,right:20}) .alignItems(HorizontalAlign.Start) .width('100%') }.width('100%') .padding({bottom:20}) Column(){ Text(`共${this.CatalogListLength}章`).fontSize(18).width('100%').textAlign(TextAlign.Start).padding({left:5,bottom:20}) List({ space: 16 }) { LazyForEach(this.data, (item: CatalogItem, index: number) => { ListItem() { catalogChild({data: item}) .onClick(()=>{ this.getRead(item.book_id,item.sort) animateTo({ duration: 200 }, () => { this.showCatalog = false }) }) } }, (item: CatalogItem, index: number) => index.toString()) }.cachedCount(5) .width('100%') .layoutWeight(1) .padding({left:10,right:10,bottom:110}) } .height('100%') .width('100%') } .padding(10) .backgroundColor('#fff') .height('100%') .width('55%') .justifyContent(FlexAlign.Start) } .height('100%') .width('100%') .backgroundColor('rgba(0,0,0,0.5)') .alignItems(HorizontalAlign.Start) .onClick(()=>{ animateTo({ duration: 200 }, () => { this.showCatalog = false }) }) } } ``` ### 高性能知识点 本例使用了LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。 当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时, 框架会进行组件销毁回收以降低内存占用。 ### 参考资料 [LazyForEach:数据懒加载](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-rendering-control-lazyforeach-0000001820879609) [List](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list-0000001862607449) [Swiper](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-swiper-0000001862607461) [@Link装饰器:父子双向同步](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-link-0000001820999565#ZH-CN_TOPIC_0000001820999565__%E7%AE%80%E5%8D%95%E7%B1%BB%E5%9E%8B%E5%92%8C%E7%B1%BB%E5%AF%B9%E8%B1%A1%E7%B1%BB%E5%9E%8B%E7%9A%84link) [HarmonyOS 5.0.0(12) 版本的配套文档](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/learning-arkts-V5)