网站想改版 权重,最近十大新闻,下载用的网站怎么做,网站被k是怎么回事HarmonyOS 组件复用面试宝典 #x1f4da; #x1f4bc; 面试加薪必备#xff01; HarmonyOS 组件复用知识点全梳理 #x1f525; 面试高频考点#xff1a;从原理到实战#xff0c;一文搞定组件复用 #x1f4a1; 适合人群#xff1a;准备 HarmonyOS 面试的前端/移动端…HarmonyOS 组件复用面试宝典 面试加薪必备 HarmonyOS 组件复用知识点全梳理 面试高频考点从原理到实战一文搞定组件复用 适合人群准备 HarmonyOS 面试的前端/移动端开发者 前言
在 HarmonyOS 面试中组件复用是一个高频考点很多候选人能说出基本概念但一涉及到具体实现和优化技巧就卡壳了。
本文将以面试问答的形式帮你彻底搞懂组件复用的方方面面让你在面试中脱颖而出 本文涵盖
✅ 组件复用核心原理和应用场景✅ 两大复用场景的具体实现含完整代码✅ 高级优化技巧和性能调优✅ 常见面试陷阱和加分项 面试官什么是组件复用为什么要用它
答 组件复用是指自定义组件从组件树上移除后被放入缓存池后续在创建相同类型的组件节点时直接复用缓存池中的组件对象。
为什么要用组件复用
避免频繁创建销毁减少内存回收频率降低性能开销提升显示效率复用缓存组件可以直接绑定数据显示比创建新视图计算开销更低解决长列表卡顿在大量数据列表快速滑动时避免列表项反复创建销毁导致的卡顿
典型应用场景
长列表滑动List、Grid、WaterFlow、Swiper 等界面中反复切换条件渲染的复杂组件树 面试官组件复用有哪些应用场景
根据实际开发主要分为两大场景
1️⃣ 同一列表内的组件复用
列表项结构类型相同列表项结构类型不同列表项内子组件可拆分组合
2️⃣ 多个列表间的组件复用
不同页面间的列表项复用 面试官组件复用的实现原理是什么 实现过程 组件回收标记了Reusable的自定义组件从组件树移除后对象实例被放入 CustomNode 虚拟结点 缓存管理RecycleManager 根据复用标识reuseId分组形成 CachedRecycleNodes 集合复用缓存池 组件复用需要新组件时优先从缓存池中查找对应reuseId的视图对象绑定新数据后重用 ️ 面试官如何实现组件复用开发流程是什么
核心开发流程
定义可复用组件使用Reusable装饰器修饰实现复用回调实现aboutToReuse()生命周期回调设置复用标识使用reuseId划分组件复用组别
⚠️ 注意事项
Reusable修饰的组件需要布局在同一个父组件下才能实现缓存复用不建议在Reusable组件中嵌套使用另一个Reusable组件 场景一同一列表内的组件复用 列表项结构类型相同 面试官这种场景怎么实现
实现步骤
将列表项封装为自定义组件ItemView添加Reusable修饰在ItemView组件内的aboutToReuse()方法中进行新数据绑定在列表的LazyForEach中使用ItemView组件设置reuseId
示例代码
Reusable
Component
struct ItemView {State item: ItemData new ItemData();aboutToReuse(params: Recordstring, Object) {this.item params.item as ItemData;}build() {Row() {Text(this.item.title).fontSize(16)Text(this.item.content).fontSize(14)}.width(100%).padding(16)}
}// 在List中使用
List() {LazyForEach(this.dataSource, (item: ItemData) {ListItem() {ItemView({ item: item })}.reuseId(item_view)})
}列表项结构类型不同 面试官多种类型的列表项如何复用
答 将不同类型的列表项分别作为复用单位各自维护独立的缓存池。
实现步骤
将不同类型的列表项分别封装为自定义组件添加Reusable修饰在组件内的aboutToReuse()方法中进行数据绑定在列表的LazyForEach中根据业务逻辑进行 if 条件选择分别设置不同的reuseId
示例代码
Reusable
Component
struct TextItemView {State item: ItemData new ItemData();aboutToReuse(params: Recordstring, Object) {this.item params.item as ItemData;}build() {Column() {Text(this.item.title).fontSize(16)Text(this.item.content).fontSize(14)}}
}Reusable
Component
struct ImageItemView {State item: ItemData new ItemData();aboutToReuse(params: Recordstring, Object) {this.item params.item as ItemData;}build() {Column() {Text(this.item.title).fontSize(16)Image(this.item.imageUrl).width(200).height(150)}}
}// 在List中使用
List() {LazyForEach(this.dataSource, (item: ItemData) {ListItem() {if (item.type text) {TextItemView({ item: item }).reuseId(text_item)} else if (item.type image) {ImageItemView({ item: item }).reuseId(image_item)}}})
}列表项内子组件可拆分组合 面试官如果列表项可以拆分为更小的子组件怎么办
答 创建多种复用子组件通过子组件的选择组合实现不同类型的列表项。
实现步骤
将单图、多图、视频、顶部标题、底部时间等分别封装为子组件添加Reusable修饰在组件内的aboutToReuse()方法中进行数据绑定通过组合子组件实现三个不同的Builder函数在列表的LazyForEach中根据业务逻辑调用相应的Builder函数
示例代码
// 可复用的子组件
Reusable
Component
struct TitleComponent {State title: string ;aboutToReuse(params: Recordstring, Object) {this.title params.title as string;}build() {Text(this.title).fontSize(16).fontWeight(FontWeight.Bold)}
}Reusable
Component
struct SingleImageComponent {State imageUrl: string ;aboutToReuse(params: Recordstring, Object) {this.imageUrl params.imageUrl as string;}build() {Image(this.imageUrl).width(100%).height(200)}
}Reusable
Component
struct TimeComponent {State time: string ;aboutToReuse(params: Recordstring, Object) {this.time params.time as string;}build() {Text(this.time).fontSize(12).fontColor(Color.Gray)}
}// Builder函数组合子组件
Builder
function SingleImageItemBuilder(item: ItemData) {Column() {TitleComponent({ title: item.title })SingleImageComponent({ imageUrl: item.imageUrl })TimeComponent({ time: item.time })}
}Builder
function TextOnlyItemBuilder(item: ItemData) {Column() {TitleComponent({ title: item.title })Text(item.content).fontSize(14)TimeComponent({ time: item.time })}
}// 在List中使用
List() {LazyForEach(this.dataSource, (item: ItemData) {ListItem() {if (item.type single_image) {SingleImageItemBuilder(item)} else if (item.type text_only) {TextOnlyItemBuilder(item)}}})
}面试官为什么用Builder 而不是自定义组件嵌套
答 因为缓存池位于自定义组件上嵌套子组件会将缓存池分割导致复用不生效。使用Builder可以使内部的自定义组件汇聚在同一个缓存池里实现相互复用。 场景二多个列表间的组件复用 场景描述 面试官不同页面的列表如何实现组件复用
答 采用 SwiperList 实现自定义全局复用缓存池 NodePool利用 BuilderNode 的节点复用能力。 实现原理 核心思路
使用NodeContainer占位继承NodeController实现 NodeItem 结点类当 NodeItem 即将销毁时回收到 NodePool 缓存池创建组件时优先从缓存池查找未找到则新建 面试官为什么不用 TabsList
答 Tabs 内容页不支持 LazyForEach只能使用 ForEachTabContent。ForEach 会一次性创建所有 TabContent页面切换时不执行aboutToDisappear()无法回收组件。 开发步骤
实现 NodeItem 类继承 NodeController实现 makeNode()方法实现 NodePool 工具类单例模式管理组件复用逻辑 getNode()根据 type 获取 NodeItemrecycleNode()根据 type 回收到缓存池 封装占位组件在生命周期中取缓存、回收、复用封装视图组件使用 listItemBuilder 函数导出列表中使用将视图组件 wrapBuilder 后传递给占位组件
示例代码
// 1. NodeItem类实现
class NodeItem extends NodeController {private node: BuilderNode[ItemData] | null null;private nodeBuilder: WrappedBuilder[ItemData] | null null;public data: ItemData new ItemData();makeNode(uiContext: UIContext): FrameNode | null {if (this.node null) {this.node new BuilderNode(uiContext);this.node.build(this.nodeBuilder!, this.data);} else {// 复用时更新数据this.node.update(this.data);}return this.node?.getFrameNode();}aboutToDisappear() {// 回收到NodePoolNodePool.getInstance().recycleNode(item_type, this);}
}// 2. NodePool工具类
class NodePool {private static instance: NodePool new NodePool();private nodeMap: Mapstring, NodeItem[] new Map();static getInstance(): NodePool {return NodePool.instance;}getNode(type: string, builder: WrappedBuilder[ItemData], data: ItemData): NodeItem {let nodes this.nodeMap.get(type);if (nodes nodes.length 0) {// 从缓存池获取let nodeItem nodes.pop()!;nodeItem.data data;return nodeItem;} else {// 新建NodeItemlet nodeItem new NodeItem();nodeItem.data data;return nodeItem;}}recycleNode(type: string, nodeItem: NodeItem) {if (!this.nodeMap.has(type)) {this.nodeMap.set(type, []);}// 重置数据避免复用异常nodeItem.data new ItemData();this.nodeMap.get(type)!.push(nodeItem);}
}// 3. 占位组件
Component
struct NodeItemComponent {State nodeItem: NodeItem new NodeItem();private data: ItemData new ItemData();private builder: WrappedBuilder[ItemData] wrapBuilder(listItemBuilder);aboutToAppear() {this.nodeItem NodePool.getInstance().getNode(item_type, this.builder, this.data);}aboutToDisappear() {NodePool.getInstance().recycleNode(item_type, this.nodeItem);}build() {NodeContainer(this.nodeItem).width(100%).height(80)}
}性能优化onIdle()预创建组件 面试官首次进入页面耗时较高怎么优化
答 使用onIdle()接口预创建组件将组件对象提前放入复用缓存池。
核心思路
利用每帧帧尾的空闲时间进行预创建避免集中创建导致的主线程阻塞将预创建过程平摊到多个周期
⚠️ 注意事项
准确预估组件预创建耗时将业务逻辑颗粒度拆小合理控制预创建数量避免内存占用过多 更多优化技巧 使用 attributeUpdater 实现部分刷新
面试官如何避免组件全部属性刷新
反例 直接使用状态变量赋值导致全部属性刷新
// 导致组件全部属性刷新
aboutToReuse(params: Object) {this.fontColor params.fontColor;
}正例 使用 attributeUpdater 精准刷新
aboutToReuse(params: Object) {this.textUpdater?.updateFontColor(params.fontColor);
}使用Link/ObjectLink 替代Prop
面试官为什么建议用Link/ObjectLink
答 Prop装饰变量时会进行深拷贝增加创建时间和内存消耗而Link/ObjectLink变量共享同一地址。
反例
Component
struct ItemView {Prop moment: MomentData;
}正例
Component
struct ItemView {ObjectLink moment: MomentData;
}避免重复赋值自动更新的状态变量
面试官什么情况下不需要在 aboutToReuse()中赋值
答 如果使用了Link/ObjectLink/Prop等自动同步数据的状态变量不需要在aboutToReuse()中重复赋值。 使用 reuseId 标记布局变化组件
面试官if/else 条件语句如何优化复用
反例 不使用 reuseId 可能导致组件重复创建/删除
if (condition) {Flex() {Image($r(app.media.icon))}
}正例 根据分支逻辑设置不同 reuseId
if (condition) {Flex() {Image($r(app.media.icon))}.reuseId(with_image)
} else {Flex() {Text(无图片)}.reuseId(without_image)
}避免函数方法作为复用组件入参
面试官复用组件的入参有什么注意事项
反例 函数作为入参每次复用都会执行
// 每次复用都执行countAndReturn()
ItemView({ sum: this.countAndReturn(item.value) });正例 提前计算通过状态变量传递
// 页面初始化时计算
this.sum this.countAndReturn(item.value);
// 复用时直接传递结果
ItemView({ sum: this.sum });面试官如何检查组件复用是否生效
检查方法 Code Linter 扫描关注performance/hp-arkui-use-reusable-component规则 Profiler 工具抓取 Trace 搜索组件名称查看 BuildRecycle 字段识别是否发生丢帧判断子组件创建次数 性能分析通过 Trace 识别懒加载渲染流程 文章转载自: http://www.morning.kdbcx.cn.gov.cn.kdbcx.cn http://www.morning.tcxzn.cn.gov.cn.tcxzn.cn http://www.morning.kzcfr.cn.gov.cn.kzcfr.cn http://www.morning.lbpfl.cn.gov.cn.lbpfl.cn http://www.morning.tfpqd.cn.gov.cn.tfpqd.cn http://www.morning.rsnd.cn.gov.cn.rsnd.cn http://www.morning.mhbcy.cn.gov.cn.mhbcy.cn http://www.morning.youngbase.cn.gov.cn.youngbase.cn http://www.morning.youngbase.cn.gov.cn.youngbase.cn http://www.morning.nxstj.cn.gov.cn.nxstj.cn http://www.morning.pswzc.cn.gov.cn.pswzc.cn http://www.morning.rahllp.com.gov.cn.rahllp.com http://www.morning.plqhb.cn.gov.cn.plqhb.cn http://www.morning.mgtmm.cn.gov.cn.mgtmm.cn http://www.morning.bkfdf.cn.gov.cn.bkfdf.cn http://www.morning.wjlnz.cn.gov.cn.wjlnz.cn http://www.morning.nfbkz.cn.gov.cn.nfbkz.cn http://www.morning.cfnsn.cn.gov.cn.cfnsn.cn http://www.morning.hcqpc.cn.gov.cn.hcqpc.cn http://www.morning.mjytr.cn.gov.cn.mjytr.cn http://www.morning.brkc.cn.gov.cn.brkc.cn http://www.morning.nfcxq.cn.gov.cn.nfcxq.cn http://www.morning.nlysd.cn.gov.cn.nlysd.cn http://www.morning.kgmkl.cn.gov.cn.kgmkl.cn http://www.morning.xpzkr.cn.gov.cn.xpzkr.cn http://www.morning.fblkr.cn.gov.cn.fblkr.cn http://www.morning.zylzk.cn.gov.cn.zylzk.cn http://www.morning.rpwck.cn.gov.cn.rpwck.cn http://www.morning.rszwc.cn.gov.cn.rszwc.cn http://www.morning.tgtrk.cn.gov.cn.tgtrk.cn http://www.morning.byjwl.cn.gov.cn.byjwl.cn http://www.morning.pgxjl.cn.gov.cn.pgxjl.cn http://www.morning.hwbmn.cn.gov.cn.hwbmn.cn http://www.morning.sbwr.cn.gov.cn.sbwr.cn http://www.morning.slzkq.cn.gov.cn.slzkq.cn http://www.morning.nrxsl.cn.gov.cn.nrxsl.cn http://www.morning.xrlwr.cn.gov.cn.xrlwr.cn http://www.morning.bksbx.cn.gov.cn.bksbx.cn http://www.morning.glnxd.cn.gov.cn.glnxd.cn http://www.morning.thrgp.cn.gov.cn.thrgp.cn http://www.morning.lkkkf.cn.gov.cn.lkkkf.cn http://www.morning.tnktt.cn.gov.cn.tnktt.cn http://www.morning.nxfwf.cn.gov.cn.nxfwf.cn http://www.morning.bfycr.cn.gov.cn.bfycr.cn http://www.morning.rbxsk.cn.gov.cn.rbxsk.cn http://www.morning.ykyfq.cn.gov.cn.ykyfq.cn http://www.morning.gxtbn.cn.gov.cn.gxtbn.cn http://www.morning.tytly.cn.gov.cn.tytly.cn http://www.morning.gjxr.cn.gov.cn.gjxr.cn http://www.morning.qpsxz.cn.gov.cn.qpsxz.cn http://www.morning.fbnsx.cn.gov.cn.fbnsx.cn http://www.morning.qwdqq.cn.gov.cn.qwdqq.cn http://www.morning.lanyee.com.cn.gov.cn.lanyee.com.cn http://www.morning.fkyrk.cn.gov.cn.fkyrk.cn http://www.morning.ubpsa.cn.gov.cn.ubpsa.cn http://www.morning.wbdm.cn.gov.cn.wbdm.cn http://www.morning.jfjfk.cn.gov.cn.jfjfk.cn http://www.morning.pbzlh.cn.gov.cn.pbzlh.cn http://www.morning.pwppk.cn.gov.cn.pwppk.cn http://www.morning.ckzjl.cn.gov.cn.ckzjl.cn http://www.morning.gbhsz.cn.gov.cn.gbhsz.cn http://www.morning.fllfc.cn.gov.cn.fllfc.cn http://www.morning.bgdk.cn.gov.cn.bgdk.cn http://www.morning.bqdpy.cn.gov.cn.bqdpy.cn http://www.morning.mwwnz.cn.gov.cn.mwwnz.cn http://www.morning.qcdhg.cn.gov.cn.qcdhg.cn http://www.morning.wgcng.cn.gov.cn.wgcng.cn http://www.morning.qmncj.cn.gov.cn.qmncj.cn http://www.morning.pqrhb.cn.gov.cn.pqrhb.cn http://www.morning.tkxyx.cn.gov.cn.tkxyx.cn http://www.morning.mlcnh.cn.gov.cn.mlcnh.cn http://www.morning.bswnf.cn.gov.cn.bswnf.cn http://www.morning.fwkq.cn.gov.cn.fwkq.cn http://www.morning.zffn.cn.gov.cn.zffn.cn http://www.morning.jfwbr.cn.gov.cn.jfwbr.cn http://www.morning.dbqg.cn.gov.cn.dbqg.cn http://www.morning.mdtfh.cn.gov.cn.mdtfh.cn http://www.morning.yrnrr.cn.gov.cn.yrnrr.cn http://www.morning.msmtf.cn.gov.cn.msmtf.cn http://www.morning.wdlyt.cn.gov.cn.wdlyt.cn