HarmonyOS7 多类型列表项复用怎么拆组件
文章目录
项目 Git 地址:https://gitcode.com/HarmonyOS_Samples/component-reuse
真实的信息流,很少所有卡片都长一样。
有的只有文字,有的右边带一张图,有的直接三张图横排。这个时候还想做组件复用,就不能只靠一个 ItemView 走天下了。

项目里的 MultiTypeItemPage.ets 正好讲这个场景。
页面效果先看一眼

这个页面里混着不同样式的列表项。看起来像普通新闻流,但代码里已经按类型拆好了组件。
数据用 type 区分结构
模拟数据里,每条 ItemData 都有一个 type:
export class ItemData {
id: string = '';
type: number = 0;
pics: Resource[] = [];
preview: Resource | string = '';
}
MockData.ets 里生成数据时这样写:
const data = new ItemData('' + i, i % 3);
也就是说,type 会在 0、1、2 之间轮换。
这三个值刚好对应三种卡片结构。
LazyForEach 里按类型选择组件
核心代码在这里:
LazyForEach(this.dataSource, (item: ItemData) => {
if (item.type === 0) {
TextTypeItemView({ item: item })
.reuseId('text_item_id')
} else if (item.type === 1) {
ImageTypeItemView({ item: item })
.reuseId('image_item_id')
} else if (item.type === 2) {
ThreeImageTypeItemView({ item: item })
.reuseId('three_image_item_id')
}
}, (item: ItemData) => item.id.toString())
这段逻辑很直白:
type === 0:纯文本卡片。type === 1:右侧单图卡片。type === 2:三图卡片。
你可以把它理解成一个轻量版的列表项工厂。
三个组件都加了 @Reusable
项目没有把三个结构塞进一个组件里硬判断,而是拆成三个组件:
@Reusable
@Component
struct TextTypeItemView {
@ObjectLink item: ItemData;
}
@Reusable
@Component
struct ImageTypeItemView {
@ObjectLink item: ItemData;
}
@Reusable
@Component
struct ThreeImageTypeItemView {
@ObjectLink item: ItemData;
}
这个拆法我比较推荐。
如果全塞进一个大组件,代码短期看着少,后面状态和布局会越来越乱。按结构拆开,复用池也更清楚。
为什么每个类型要独立 reuseId
这点非常重要。
项目分别用了:
.reuseId('text_item_id')
.reuseId('image_item_id')
.reuseId('three_image_item_id')
因为三种卡片结构不同。
纯文本卡片没有图片区域,单图卡片右侧有图片,三图卡片中间有图片 Row。如果它们共用一个 reuseId,框架可能拿一个旧的单图组件去显示纯文本数据,风险就来了。
复用的前提是结构能匹配。
这种拆法适合业务扩展
假设后面加一个视频卡片,你只需要:
else if (item.type === 3) {
VideoTypeItemView({ item: item })
.reuseId('video_item_id')
}
然后新增一个 VideoTypeItemView。
旧的三种组件不用动太多,复用池也不会被污染。
小白别急着优化 if else
有人会觉得 if else 不够优雅,想上来就写映射表、工厂类。
我建议先别急。
在 ArkUI 页面里,结构分支本来就很常见。等类型真的多到维护困难,再抽象也不迟。这个项目现在这样写,反而更适合学习。
看看三种卡片到底差在哪
纯文本卡片只需要标题、来源和时间:
@Reusable
@Component
struct TextTypeItemView {
@ObjectLink item: ItemData;
build() {
Column() {
Text(this.item.title)
.maxLines(3)
Row() {
Text(this.item.from)
Text(this.item.tail)
}
}
}
}
单图卡片多了右侧图片:
@Reusable
@Component
struct ImageTypeItemView {
@ObjectLink item: ItemData;
build() {
Row() {
Column() {
Text(this.item.title)
Text(this.item.tail)
}
.layoutWeight(1)
Image(this.item.preview)
.width(96)
.height(78)
.borderRadius(8)
}
}
}
三图卡片中间是三张图:
@Reusable
@Component
struct ThreeImageTypeItemView {
@ObjectLink item: ItemData;
build() {
Column() {
Text(this.item.title)
Row() {
Image(this.item.pics[0]).layoutWeight(1)
Image(this.item.pics[1]).layoutWeight(1)
Image(this.item.pics[2]).layoutWeight(1)
}
Text(this.item.tail)
}
}
}
把这三段放在一起,你会发现它们不是“数据不同”,而是“结构不同”。结构不同,就要拆组件,也要拆 reuseId。
新增一种卡片该怎么做
真实业务里经常会加新类型,比如视频卡片。照这个项目的思路,你要做三件事:
// 1. 数据里约定 type === 3 表示视频卡片
else if (item.type === 3) {
VideoTypeItemView({ item: item })
.reuseId('video_item_id')
}
// 2. 新建视频卡片组件
@Reusable
@Component
struct VideoTypeItemView {
@ObjectLink item: ItemData;
build() {
Stack({ alignContent: Alignment.BottomEnd }) {
Image(this.item.preview)
Text(this.item.duration)
}
}
}
第三件事最容易忘:确认 video_item_id 不要和旧类型混用。
写在最后
多类型列表复用的核心不是“怎么少写代码”,而是“怎么把不同结构分清楚”。
组件拆清楚,reuseId 拆清楚,复用就稳很多。
更多推荐


所有评论(0)