HarmonyOS7 新闻懒加载列表页实战:LazyForEach 的关键不在“懒”,在数据源

HarmonyOS7 新闻懒加载列表页实战:LazyForEach 的关键不在“懒”,在数据源
文章目录先看 IDataSource别急着看样式数据结构要服务列表更新NewsDataSource 是这个案例的核心加载更多要挡住重复点击列表项只是表现层完整代码写在最后新闻流、商品流、评论流这类页面最怕一上来把所有内容都铺出来。数据一多页面首屏慢、滚动卡、内存压力也跟着上来。LazyForEach解决的就是这个问题只渲染当前需要看到的内容。这个案例用新闻列表来讲比单独贴 API 更容易理解因为它同时包含数据源、列表项、加载更多和滚动触发。先看IDataSource别急着看样式LazyForEach不是直接吃一个普通数组就完事它依赖数据源对象告诉框架一共有多少条、某个位置的数据是什么、数据变化时该通知谁。所以这篇最值得看的不是新闻卡片怎么排版而是NewsDataSource这层封装。它把dataArray和listeners放在一起列表新增数据时通过监听器通知视图更新。数据结构要服务列表更新NewsItem_nibl保存了标题、来源、时间、分类、图标、是否热门等字段。字段看起来不少但都和列表渲染直接相关标题控制主内容分类控制标签样式isHot控制热门标记。页面里的totalItems、renderedItems、isLoadingMore则是运行时状态。一个负责告诉用户当前数据规模一个记录可视区域数量一个防止重复触发加载更多。大列表写顺了基本都离不开这几类状态。NewsDataSource是这个案例的核心下面这段构造函数很简单但它说明了数据源的入口页面创建数据源时把初始新闻数组交进去后续列表只通过数据源读取。constructor(items:NewsItem_nibl[]){this.dataArrayitems}真正要注意的是后面的totalCount()、getData()和addItem()。前两个负责让LazyForEach知道“有多少、取哪条”addItem()负责追加数据后通知监听器。如果只改数组、不通知视图懒加载列表很容易出现数据已经变了但界面没刷新的问题。加载更多要挡住重复点击loadMore()一开始就判断isLoadingMore这是必要的。滚动到底部时onScrollIndex()可能连续触发如果没有这个锁短时间内会发起多次加载新闻列表会重复插入一批数据。这个案例用setTimeout()模拟网络请求真实项目里可以换成接口调用。核心思路不变进入加载态、追加数据、退出加载态。列表项只是表现层新闻卡片里的图标、标题、标签、来源和浏览量都只是表现层。LazyForEach(this.dataSource, ...)才是列表性能的重点。它让页面随着滚动按需构建条目而不是把 50 条、100 条甚至更多内容一次性压进视图树。完整代码下面是整理后的完整代码入口组件名已经换成LazyNewsListPage可以直接按项目路由规则接入。// LazyForEach 懒加载与列表性能优化// 懒加载数据源IDataSource 实现classNewsDataSourceimplementsIDataSource{privatedataArray:NewsItem_nibl[][]privatelisteners:DataChangeListener[][]constructor(items:NewsItem_nibl[]){this.dataArrayitems}totalCount():number{returnthis.dataArray.length}getData(index:number):NewsItem_nibl{returnthis.dataArray[index]}registerDataChangeListener(listener:DataChangeListener):void{this.listeners.push(listener)}unregisterDataChangeListener(listener:DataChangeListener):void{constidxthis.listeners.indexOf(listener)if(idx0){this.listeners.splice(idx,1)}}addItem(item:NewsItem_nibl){this.dataArray.push(item)this.listeners.forEach(ll.onDataAdd(this.dataArray.length-1))}}interfaceNewsItem_nibl{id:numbertitle:stringsource:stringtime:stringviews:numbercategory:stringcategoryColor:stringcategoryBg:stringicon:stringisHot:boolean}EntryComponentstruct LazyNewsListPage{StatetotalItems:number0StaterenderedItems:number0StateisLoadingMore:booleanfalseprivatedataSource:NewsDataSourcenewNewsDataSource([])privateallNews:NewsItem_nibl[][]privatecategories:string[][综合,科技,财经,体育,娱乐]privateicons:string[][,,,⚽,]privatecolors:string[][#2563EB,#7C3AED,#059669,#EF4444,#D97706]privatebgs:string[][#EFF6FF,#F5F3FF,#D1FAE5,#FEE2E2,#FEF3C7]privatetitles:string[][HarmonyOS 5.0 正式发布全面支持 ArkUI 3.0,腾讯云推出新一代 AI 开发平台,A 股三大指数集体上涨科技板块领涨,世界杯预选赛中国队主场迎战对手,年度最佳电影票房突破百亿大关,OpenAI 发布 GPT-5性能大幅提升,央行宣布降准 0.5 个百分点,奥运会新增多个比赛项目,四季度财报亮眼多家科技巨头超预期,国产芯片实现新突破7nm 工艺量产,新能源汽车销量再创历史新高,互联网大厂裁员潮持续AI 岗位却逆势扩招,]aboutToAppear(){// 初始化50条数据this.generateData(50)}generateData(count:number){for(leti0;icount;i){constcatIdxi%5constitemIdthis.allNews.length1constnewsItem:NewsItem_nibl{id:itemId,title:this.titles[i%this.titles.length]${itemId},source:[新华社,人民日报,第一财经,澎湃新闻,科技日报][i%5],time:${i%24}小时前,views:Math.floor(Math.random()*10000)500,category:this.categories[catIdx],categoryColor:this.colors[catIdx],categoryBg:this.bgs[catIdx],icon:this.icons[catIdx],isHot:i%70}this.allNews.push(newsItem)this.dataSource.addItem(newsItem)}this.totalItemsthis.allNews.length}loadMore(){if(this.isLoadingMore)returnthis.isLoadingMoretruesetTimeout((){this.generateData(20)this.isLoadingMorefalse},1000)}build(){Column({space:0}){// 标题与性能指示Row(){Column({space:2}){Text(LazyForEach 懒加载).fontSize(18).fontWeight(FontWeight.Bold).fontColor(#111827)Text(大列表性能优化按需渲染减少内存占用).fontSize(12).fontColor(#6B7280)}.alignItems(HorizontalAlign.Start).layoutWeight(1)Column({space:2}){Text(this.totalItems.toString()).fontSize(20).fontWeight(FontWeight.Bold).fontColor(#2563EB)Text(条数据).fontSize(11).fontColor(#9CA3AF)}.alignItems(HorizontalAlign.Center)}.width(100%).padding({left:20,right:20,top:16,bottom:12}).backgroundColor(Color.White)// 说明栏Row(){Text(⚡).fontSize(14).margin({right:6})Text(LazyForEach 只渲染可视区域内的条目滚动时动态加载/销毁适合大量数据).fontSize(12).fontColor(#065F46).layoutWeight(1)}.width(100%).padding({left:16,right:16,top:8,bottom:8}).backgroundColor(#D1FAE5).alignItems(VerticalAlign.Top)// 懒加载列表List({space:0}){LazyForEach(this.dataSource,(item:NewsItem_nibl){ListItem(){Column({space:0}){Row({space:12}){// 类别图标Text(item.icon).fontSize(26).width(50).height(50).textAlign(TextAlign.Center).backgroundColor(item.categoryBg).borderRadius(10)Column({space:6}){// 标题行热门标记Row({space:6}){if(item.isHot){Text().fontSize(12)}Text(item.title).fontSize(14).fontWeight(FontWeight.Medium).fontColor(#111827).layoutWeight(1).maxLines(2).textOverflow({overflow:TextOverflow.Ellipsis}).lineHeight(20)}.width(100%).alignItems(VerticalAlign.Top)// 底部信息行Row({space:10}){Text(item.category).fontSize(11).fontColor(item.categoryColor).backgroundColor(item.categoryBg).padding({left:6,right:6,top:2,bottom:2}).borderRadius(6)Text(item.source).fontSize(11).fontColor(#9CA3AF)Text(item.time).fontSize(11).fontColor(#9CA3AF)Blank()Text( (item.views1000?(item.views/1000).toFixed(1)k:item.views.toString())).fontSize(11).fontColor(#9CA3AF)}.width(100%).alignItems(VerticalAlign.Center)}.layoutWeight(1).alignItems(HorizontalAlign.Start)}.width(100%).padding({left:16,right:16,top:12,bottom:12}).alignItems(VerticalAlign.Top).backgroundColor(Color.White)Divider().color(#F3F4F6).margin({left:78})}}},(item:NewsItem_nibl)item.id.toString())// 加载更多ListItem(){Column(){if(this.isLoadingMore){Row({space:8}){LoadingProgress().width(20).height(20).color(#2563EB)Text(加载更多...).fontSize(13).fontColor(#6B7280)}.padding({top:16,bottom:16})}else{Text(上拉加载更多还有更多内容).fontSize(13).fontColor(#9CA3AF).padding({top:16,bottom:16}).onClick(()this.loadMore())}}.width(100%).alignItems(HorizontalAlign.Center).backgroundColor(Color.White)}}.width(100%).layoutWeight(1).backgroundColor(#F9FAFB).edgeEffect(EdgeEffect.Spring).onScrollIndex((start:number,end:number){this.renderedItemsend-start1if(endthis.totalItems-5!this.isLoadingMore){this.loadMore()}})}.width(100%).height(100%).backgroundColor(#FFFFFF)}}写在最后LazyForEach真正难的地方是把数据变化和视图通知接好。只要数据源这层写稳新闻流、商品流、评论流都可以沿着同一套思路扩展。