HarmonyOS7 列表流实战------自定义列表项别一股脑塞进 build 里
文章目录
源码获取
如果你想一边对照文章一边实操,建议直接把示例工程拉到本地。项目 Git 地址:https://gitcode.com/HarmonyOS_Samples/CommonListFlows。
很多人写列表页,最开始都会经历一个阶段: 页面能出来,代码也能跑,但越写越像一堵墙。
尤其是列表项。刚开始只有一张图一行字,你会觉得塞在 build() 里也没什么。等它慢慢长出头像、来源、时间、摘要、三张配图、角标、标签,页面代码就会突然变得特别难看。
CustomListItem 这个组件虽然不大,但特别适合拿来说明一件事: 只要列表项已经形成稳定结构,就该尽早把它抽出来。
先别急着看写法,先看它像不像真实内容卡片

这个组件最像哪类东西?
我觉得特别像资讯流、社区流、推荐流里的标准卡片。一个条目里通常会有这些元素:
- 一个头像或封面图
- 一块来源信息
- 一段正文摘要
- 一排配图
这其实就是你以后最常碰到的列表卡片模型之一。
项目里的 CustomListItem 长什么样
源码本身很直白:
@Component
export struct CustomListItem {
@State title: string | ResourceStr = ''
@State imgUrl: string | ResourceStr = ''
build() {
Column() {
Row() {
Image(this.imgUrl)
.width(40)
.height(40)
.borderRadius(20)
Column() {
Text($r('app.string.security'))
Text('示例时间')
}
}
Text(this.title)
.margin({ top: 12, bottom: 12 })
Row() {
Image(this.imgUrl)
Image(this.imgUrl)
Image(this.imgUrl)
}
}
.padding(12)
.borderRadius(16)
.backgroundColor(Color.White)
}
}

这段代码本身不复杂,但拆得很像一张完整卡片:
- 顶部是来源信息区
- 中间是摘要区
- 底部是多图区
当你能从“代码块”开始切换成“卡片结构”去看问题,组件化思路就会自然很多。
为什么这类列表项更适合抽成独立组件
很多新手会问,那为什么不直接写成一个 @Builder?
当然也不是不行,但我更推荐这里用独立组件。原因非常现实:
- 复用更自然
- 页面主结构会清爽很多
- 以后加事件、状态、样式变化更方便
简单说,如果只是页面里一小段重复布局,Builder 挺好用;但只要它已经像一张“卡片”,我更建议你把它当组件看。
因为这时候它已经不是一段小 UI,而是一个完整的展示单元了。
ManagerPage 是怎么复用它的
到了 ManagerPage,页面本身不再关心卡片内部怎么排,只关心“我这里要显示几张卡片、每张卡片喂什么数据”:
List({ space: 10, scroller: this.listScroller }) {
CustomListItem({
imgUrl: $r('app.media.pic1'),
title: $r('app.string.manager_content')
})
CustomListItem({
imgUrl: $r('app.media.pic2'),
title: $r('app.string.manager_content')
})
}
你会发现,页面代码一下子轻了很多。
这就是组件化最直接的好处。主页面负责摆结构,卡片组件负责管自己长什么样。职责一分开,代码读起来就舒服得多。
这种卡片最适合怎么拆
如果你以后自己做类似卡片,我很建议你先按区域拆,而不是按控件拆。
比如 CustomListItem 就很适合先想成这三块:
- 头部信息区
- 正文摘要区
- 附件图片区
这个思路特别有用。
因为当你按区域拆时,布局会更像真实产品;如果你一上来只盯着“这里一个 Text,那里一个 Image”,最后代码往往会很碎,结构感也很差。
为什么说它特别适合小白练手
别看这只是个小组件,它其实把很多常见动作都顺手练到了:
- 圆角头像
- 文本分层
- 上下间距控制
- 横向排布
- 多图均分
- 白底卡片容器
这些能力单独拿出来都不难,但能不能把它们自然地组合成一张卡片,这才是页面感的来源。
这里有个细节,我建议你早点建立意识
项目里这样定义属性:

@State title: string | ResourceStr = ''
@State imgUrl: string | ResourceStr = ''
从示例工程角度看,这样写没问题,代码也够短。
但如果你以后做更正式的组件,我会建议你早点分清一件事: 外部传进来的展示数据,和组件内部自己维护的状态,不是一回事。
说白了,卡片标题、图片这类内容,本质上更像“输入”,不是卡片自己临时产生的“内部状态”。现在你先有这个概念,后面进阶会轻松很多。
如果你想把这个组件改成自己的风格,先改这三刀
别一上来就想着做万能组件,先把当前页面的气质改顺。
我建议你优先改这三处:
- 把顶部来源名换成你自己的演示栏目
- 把时间换成“刚刚”“10 分钟前”这种更真实的展示文案
- 把底部三图改成一张大图或两张并排图
这三刀下去,你会立刻感受到: 结构不变,页面观感却能差很多。
这类组件最常见的坏习惯,其实非常固定
列表项都重复三遍了,还不拆
短期看复制粘贴很快,后面一改样式就要全项目手抄,特别痛苦。
组件拆出来了,却把复杂业务判断也塞进去
这样会让卡片越来越重。展示组件最好先聚焦展示,复杂逻辑能留给上层就留给上层。
一上来就想做“宇宙级通用组件”
这几乎是新手通病。结果往往是参数越来越多,谁都不爱改。先把当前页面服务好,比幻想一个万能组件靠谱得多。
这篇还顺手给了一个很实在的脱敏思路
项目原始资源里有固定文案和时间示例。写教程时,我前面已经把它们改成更中性的表达,这其实就是一个很实战的习惯。
技术教程里,最好让读者知道这些只是演示数据,不是你在灌输某个固定业务场景。这样后面别人拿去改成校园资讯、社区帖子、课程推荐,也会更顺。
最后一句
列表页真正拉开差距的,不是你会不会写 List,而是你有没有在重复结构出现的时候,及时把它从主页面里拎出来。
CustomListItem 这个例子不算大,但它特别适合帮你养成一个值钱的习惯: 复杂列表项别一股脑塞进 build(),早点组件化,后面真的会轻松很多。
更多推荐


所有评论(0)