当前位置: 首页 > news >正文

网站续费通知单厦门网站建设官网

网站续费通知单,厦门网站建设官网,中天建设集团有限公司董事长,电子商务是建网站HarmonyOS 组件复用 指南 什么是组件复用#xff1f; #x1f3af; 简单理解 想象一下#xff0c;你在玩积木。当你不再需要某个积木时#xff0c;你不会把它扔掉#xff0c;而是放到一个盒子里。下次需要相同类型的积木时#xff0c;你直接从盒子里拿出来用就行了。 …HarmonyOS 组件复用 指南 什么是组件复用 简单理解 想象一下你在玩积木。当你不再需要某个积木时你不会把它扔掉而是放到一个盒子里。下次需要相同类型的积木时你直接从盒子里拿出来用就行了。 组件复用就是这个道理 组件 界面上的一个部分比如列表中的一项复用 重复使用而不是重新创建缓存池 存放积木的盒子 技术定义 组件复用是指自定义组件从组件树上移除后被放入缓存池后续在创建相同类型的组件节点时直接复用缓存池中的组件对象。 为什么需要组件复用 性能优势 没有组件复用时 用户滑动列表 → 创建新组件 → 显示内容 → 滑出屏幕 → 销毁组件↑ ↓耗时耗内存 浪费资源有组件复用时 用户滑动列表 → 从缓存取组件 → 更新内容 → 显示 → 滑出屏幕 → 放入缓存↑ ↓快速高效 循环利用实际效果 ✅ 减少内存回收频率✅ 降低 CPU 计算开销✅ 提升滑动流畅度✅ 改善用户体验 典型应用场景 长列表滑动如朋友圈、商品列表 界面切换频繁的场景 数据展示类应用 任何需要频繁创建/销毁组件的场景 组件复用的基本原理 复用流程图解 三个关键步骤 标记阶段给组件打上 Reusable 标签回收阶段组件滑出屏幕时放入缓存池复用阶段需要新组件时从缓存池取出并更新数据 关键概念解释 概念简单理解技术含义Reusable给组件贴上可重复使用的标签装饰器标记组件可复用reuseId给不同类型的组件分类存放复用标识区分缓存池aboutToReuse()组件重新上岗时的准备工作生命周期回调处理数据更新缓存池存放待复用组件的仓库CachedRecycleNodes 集合 入门实践基础列表复用 场景一相同结构的列表项 这是最简单的复用场景列表中每一项都长得一样只是内容不同。 ️ 实现步骤 第 1 步创建可复用组件 Reusable // 关键标记组件可复用 Component struct ItemView {State title: string State content: string // 关键实现复用回调aboutToReuse(params: Recordstring, Object): void {// 组件从缓存池取出时更新数据this.title params.title as stringthis.content params.content as string}build() {Column() {Text(this.title).fontSize(16).fontWeight(FontWeight.Bold)Text(this.content).fontSize(14).fontColor(Color.Gray)}.padding(10)} }第 2 步在列表中使用 Component struct ContentPage {State dataList: Arrayany [{ title: 标题1, content: 内容1 },{ title: 标题2, content: 内容2 },// ... 更多数据]build() {List() {LazyForEach(this.dataSource, (item: any) {ListItem() {ItemView({ title: item.title, content: item.content })}.reuseId(item_view) // 关键设置复用ID})}} }新手提示 Reusable 是必须的没有它就没有复用效果aboutToReuse() 是数据更新的地方不要忘记实现reuseId 用来区分不同类型的组件相同类型用相同 ID 场景二不同结构的列表项 当列表中有多种不同类型的条目时比如有些是纯文本有些带图片有些是视频。 ️ 实现步骤 第 1 步创建不同类型的组件 // 文本类型组件 Reusable Component struct TextItemView {State title: string State content: string aboutToReuse(params: Recordstring, Object): void {this.title params.title as stringthis.content params.content as string}build() {Column() {Text(this.title).fontSize(16)Text(this.content).fontSize(14)}} }// 图片类型组件 Reusable Component struct ImageItemView {State title: string State imageUrl: string aboutToReuse(params: Recordstring, Object): void {this.title params.title as stringthis.imageUrl params.imageUrl as string}build() {Column() {Text(this.title).fontSize(16)Image(this.imageUrl).width(100).height(100)}} }第 2 步根据数据类型选择组件 Component struct ContentPage {State dataList: Arrayany [{ type: text, title: 纯文本, content: 这是内容 },{ type: image, title: 带图片, imageUrl: path/to/image },// ... 更多数据]build() {List() {LazyForEach(this.dataSource, (item: any) {ListItem() {if (item.type text) {TextItemView({ title: item.title, content: item.content }).reuseId(text_item) // 不同类型用不同ID} else if (item.type image) {ImageItemView({ title: item.title, imageUrl: item.imageUrl }).reuseId(image_item) // 不同类型用不同ID}}})}} }新手提示 不同类型的组件需要不同的 reuseId每种类型都有自己的缓存池数据结构要考虑类型区分 场景三组件内部可拆分复用 有时候组件内部的某些部分可以单独复用这样可以更精细地控制复用。 ️ 实现步骤 第 1 步拆分为可复用的子组件 // 标题组件 Reusable Component struct TitleComponent {State title: string aboutToReuse(params: Recordstring, Object): void {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): void {this.imageUrl params.imageUrl as string}build() {Image(this.imageUrl).width(100).height(100)} }// 多图组件 Reusable Component struct MultiImageComponent {State imageList: Arraystring []aboutToReuse(params: Recordstring, Object): void {this.imageList params.imageList as Arraystring}build() {Row() {ForEach(this.imageList, (url: string) {Image(url).width(60).height(60).margin(2)})}} }// 底部时间组件 Reusable Component struct TimeComponent {State time: string aboutToReuse(params: Recordstring, Object): void {this.time params.time as string}build() {Text(this.time).fontSize(12).fontColor(Color.Gray)} }第 2 步用 Builder 组合不同类型 Component struct ContentPage {// 文本类型布局Builder textItemBuilder(item: any) {Column() {TitleComponent({ title: item.title }).reuseId(title_component)TimeComponent({ time: item.time }).reuseId(time_component)}}// 单图类型布局Builder singleImageItemBuilder(item: any) {Column() {TitleComponent({ title: item.title }).reuseId(title_component)SingleImageComponent({ imageUrl: item.imageUrl }).reuseId(single_image_component)TimeComponent({ time: item.time }).reuseId(time_component)}}// 多图类型布局Builder multiImageItemBuilder(item: any) {Column() {TitleComponent({ title: item.title }).reuseId(title_component)MultiImageComponent({ imageList: item.imageList }).reuseId(multi_image_component)TimeComponent({ time: item.time }).reuseId(time_component)}}build() {List() {LazyForEach(this.dataSource, (item: any) {ListItem() {if (item.type text) {this.textItemBuilder(item)} else if (item.type single_image) {this.singleImageItemBuilder(item)} else if (item.type multi_image) {this.multiImageItemBuilder(item)}}})}} }新手提示 为什么用 Builder 而不是直接嵌套组件 直接嵌套会分割缓存池导致复用失效Builder 可以保持所有组件在同一个缓存池 细粒度复用的好处 标题组件可以在所有类型间复用时间组件也可以在所有类型间复用提高了复用效率 进阶实践复杂场景应用 场景多个列表间的组件复用 当应用有多个页面每个页面都有列表我们希望不同页面的列表项也能互相复用。 问题分析 普通的组件复用只能在同一个父组件内生效。但是不同页面的列表是不同的父组件所以需要创建一个全局的复用缓存池。 ️ 解决方案 第 1 步创建全局复用池 // 单例模式的全局复用池 class NodePool {private static instance: NodePool;private cachedNodes: Mapstring, ArrayNodeItem new Map();static getInstance(): NodePool {if (!NodePool.instance) {NodePool.instance new NodePool();}return NodePool.instance;}// 获取复用节点getNode(type: string,builder: WrappedBuilder[Object],data: Object): NodeItem {let cachedArray this.cachedNodes.get(type);if (cachedArray cachedArray.length 0) {// 从缓存中取出let nodeItem cachedArray.pop()!;// 检查节点是否有效if (nodeItem.getNodePtr() ! null) {nodeItem.updateData(data);return nodeItem;}}// 创建新节点let nodeItem new NodeItem(type, builder);nodeItem.updateData(data);return nodeItem;}// 回收节点recycleNode(nodeItem: NodeItem) {let type nodeItem.getType();if (!this.cachedNodes.has(type)) {this.cachedNodes.set(type, []);}// 重置节点状态nodeItem.resetState();this.cachedNodes.get(type)!.push(nodeItem);} }第 2 步创建节点包装类 class NodeItem extends NodeController {private type: string;private builder: WrappedBuilder[Object];private data: Object {};private node: BuilderNode[Object] | null null;constructor(type: string, builder: WrappedBuilder[Object]) {super();this.type type;this.builder builder;}makeNode(uiContext: UIContext): FrameNode | null {if (this.node null) {this.node new BuilderNode(uiContext, { builder: this.builder });}// 更新数据this.node.update(this.data);return this.node.getFrameNode();}updateData(data: Object) {this.data data;}getType(): string {return this.type;}resetState() {// 重置状态避免复用时显示异常this.data {};} }第 3 步创建复用组件包装器 Component struct ReusableItemWrapper {Prop type: stringProp data: ObjectProp builder: WrappedBuilder[Object]private nodeItem: NodeItem | null nullaboutToAppear() {// 从全局复用池获取节点this.nodeItem NodePool.getInstance().getNode(this.type, this.builder, this.data)}aboutToDisappear() {// 回收到全局复用池if (this.nodeItem) {NodePool.getInstance().recycleNode(this.nodeItem)}}build() {NodeContainer(this.nodeItem).height(100)} }第 4 步在列表中使用 // 定义列表项视图 Builder function listItemBuilder(data: Object) {let item data as ItemDataColumn() {Text(item.title).fontSize(16)Text(item.content).fontSize(14)}.padding(10) }Component struct NewsPage {State newsList: ArrayItemData []build() {List() {LazyForEach(this.dataSource, (item: ItemData) {ListItem() {ReusableItemWrapper({type: news_item,data: item,builder: wrapBuilder(listItemBuilder)})}})}} }Component struct HotPage {State hotList: ArrayItemData []build() {List() {LazyForEach(this.dataSource, (item: ItemData) {ListItem() {ReusableItemWrapper({type: news_item, // 相同类型可以复用data: item,builder: wrapBuilder(listItemBuilder)})}})}} }新手提示 全局复用池比较复杂建议先掌握基础复用可以使用现成的三方库nodepool注意控制缓存池大小避免内存占用过多 性能优化使用 onIdle() 预创建组件 问题 首次进入页面时由于缓存池为空所有组件都需要重新创建可能导致卡顿。 解决方案 利用每帧的空闲时间提前创建一些组件放入缓存池。 class IdleCallback extends FrameCallback {private preCreateData: Arrayanyprivate currentIndex: number 0constructor(data: Arrayany) {super()this.preCreateData data}onIdle(idleTimeInNano: number): void {// 假设每个组件预创建耗时 1ms 1000000nsconst singleComponentTime 1000000let remainingTime idleTimeInNanowhile (remainingTime singleComponentTime this.currentIndex this.preCreateData.length) {// 预创建组件let data this.preCreateData[this.currentIndex]NodePool.getInstance().preBuild(data.type, data.builder)this.currentIndexremainingTime - singleComponentTime}// 如果还有未创建的组件继续下一帧if (this.currentIndex this.preCreateData.length) {this.postFrameCallback(this)}} }// 使用方式 Entry Component struct MainPage {aboutToAppear() {// 页面加载时开始预创建let preCreateData [{ type: news_item, builder: wrapBuilder(listItemBuilder) },{ type: hot_item, builder: wrapBuilder(listItemBuilder) },// ... 更多类型]let callback new IdleCallback(preCreateData)this.getUIContext().postFrameCallback(callback)} }新手提示 预创建要适量创建太多会占用内存根据实际需求调整统计常用的组件类型监控性能确保预创建本身不影响性能 高级技巧性能优化 技巧一使用 attributeUpdater 精确刷新 问题 默认情况下更新组件数据会导致整个组件重新渲染即使只改变了一个属性。 解决方案 使用 attributeUpdater 只更新需要改变的属性。 ❌ 不推荐的做法 Reusable Component struct ItemView {State title: string State fontColor: Color Color.BlackaboutToReuse(params: Recordstring, Object): void {this.title params.title as stringthis.fontColor params.fontColor as Color // 导致整个组件刷新}build() {Text(this.title).fontColor(this.fontColor).fontSize(16)} }✅ 推荐的做法 Reusable Component struct ItemView {State title: string State fontColor: Color Color.Blackprivate textUpdater: AttributeUpdaterTextAttribute new AttributeUpdater()aboutToReuse(params: Recordstring, Object): void {this.title params.title as string// 只更新颜色属性不触发整个组件刷新this.textUpdater.fontColor(params.fontColor as Color)}build() {Text(this.title).attributeUpdater(this.textUpdater) // 绑定属性更新器.fontSize(16)} }技巧二使用 Link/ObjectLink 替代 Prop 问题 Prop 会进行深拷贝增加创建时间和内存消耗。 解决方案 使用 Link 或 ObjectLink 共享数据引用。 ❌ 不推荐的做法 Reusable Component struct ItemView {Prop item: ItemData // 会进行深拷贝aboutToReuse(params: Recordstring, Object): void {this.item params.item as ItemData} }✅ 推荐的做法 Observed class ItemData {title: string content: string }Reusable Component struct ItemView {ObjectLink item: ItemData // 共享引用自动同步aboutToReuse(params: Recordstring, Object): void {// 不需要重新赋值数据会自动同步} }技巧三合理使用 reuseId 区分组件 问题 组件内部使用 if/else 切换布局时可能导致组件结构变化影响复用效果。 解决方案 为不同的布局分支设置不同的 reuseId。 ❌ 不推荐的做法 Reusable Component struct ItemView {State hasImage: boolean falsebuild() {Column() {Text(标题)if (this.hasImage) {Flex() { // 结构变化时可能需要重新创建Image(image.png)}}}} }✅ 推荐的做法 Reusable Component struct ItemView {State hasImage: boolean falsebuild() {Column() {Text(标题)if (this.hasImage) {Flex() {Image(image.png)}.reuseId(with_image) // 不同布局用不同ID} else {Flex().reuseId(without_image) // 不同布局用不同ID}}} }技巧四避免函数作为组件参数 问题 函数作为参数时每次复用都会重新执行造成性能损耗。 解决方案 提前计算结果通过状态变量传递。 ❌ 不推荐的做法 Reusable Component struct ItemView {Prop sum: number 0aboutToReuse(params: Recordstring, Object): void {// 每次复用都会执行这个耗时函数this.sum (params.calculator as Function)()} }// 使用时 ItemView({ sum: this.countAndReturn() }) // 耗时函数✅ 推荐的做法 Component struct ParentView {State calculatedSum: number 0aboutToAppear() {// 只在初始化时计算一次this.calculatedSum this.countAndReturn()}build() {List() {LazyForEach(this.dataSource, (item: any) {ListItem() {ItemView({ sum: this.calculatedSum }) // 直接传递结果}})}} }常见问题解答 ❓ 如何检查组件复用是否生效 方法一使用 Code Linter 工具 # 在 DevEco Studio 中 1. 打开 Tools Code Linter 2. 关注 performance/hp-arkui-use-reusable-component 规则 3. 查看代码检查结果方法二使用 Profiler 工具 # 在 DevEco Studio 中 1. 打开 Profiler 工具 2. 抓取 Trace 数据 3. 搜索组件名称 4. 查看是否有 BuildRecycle 字段方法三添加日志调试 Reusable Component struct ItemView {State title: string aboutToReuse(params: Recordstring, Object): void {console.log(组件复用成功:, this.title, -, params.title) // 添加日志this.title params.title as string}aboutToAppear() {console.log(创建新组件:, this.title) // 添加日志} }❓ 复用不生效的常见原因 1. 忘记添加 Reusable 装饰器 // ❌ 错误 Component struct ItemView {// ... }// ✅ 正确 Reusable Component struct ItemView {// ... }2. 没有实现 aboutToReuse 方法 // ❌ 错误 Reusable Component struct ItemView {// 没有 aboutToReuse 方法 }// ✅ 正确 Reusable Component struct ItemView {aboutToReuse(params: Recordstring, Object): void {// 实现数据更新逻辑} }3. 组件不在同一父组件下 // ❌ 错误不同的父组件 Component struct PageA {build() {List() {// ItemView 在 PageA 下}} }Component struct PageB {build() {List() {// ItemView 在 PageB 下无法复用 PageA 的}} }// ✅ 正确在同一父组件下 Component struct ParentPage {build() {Swiper() {PageA()PageB()// 两个页面在同一父组件下}} }❓ 性能优化建议 1. 控制缓存池大小 class NodePool {private maxCacheSize: number 20; // 限制缓存数量recycleNode(nodeItem: NodeItem) {let cachedArray this.cachedNodes.get(type);if (cachedArray cachedArray.length this.maxCacheSize) {return; // 超过限制就不缓存}// ... 正常缓存逻辑} }2. 监控内存使用 Component struct MainPage {aboutToAppear() {// 定期清理缓存setInterval(() {NodePool.getInstance().clearCache()}, 300000) // 5分钟清理一次} }3. 合理选择复用粒度 粗粒度复用整个列表项作为一个复用单位 优点简单易用缺点复用率可能不高 细粒度复用将列表项拆分成多个小组件 优点复用率高性能更好缺点代码复杂度增加 ❓ 最佳实践总结 ✅ 应该做的事情 优先使用基础复用从简单场景开始合理设置 reuseId相同类型用相同 ID及时更新数据在 aboutToReuse 中处理控制缓存大小避免内存泄漏性能监控定期检查复用效果 ❌ 不应该做的事情 嵌套 Reusable 组件会导致缓存池分割频繁改变组件结构影响复用效率忽略内存管理可能导致内存泄漏过度优化简单场景不需要复杂的复用逻辑 实战练习 练习 1基础列表复用 创建一个简单的联系人列表实现基础的组件复用。 需求 显示联系人姓名和电话支持滑动浏览实现组件复用优化 提示 使用 Reusable 装饰器实现 aboutToReuse 方法设置合适的 reuseId 练习 2多类型列表复用 创建一个新闻列表包含文本、图片、视频三种类型。 需求 支持多种类型的新闻条目不同类型有不同的布局实现类型间的复用优化 提示 为不同类型创建不同组件使用不同的 reuseId 区分根据数据类型选择合适的组件 练习 3全局复用池 实现一个多页面应用不同页面的列表项可以互相复用。 需求 多个页面都有相似的列表页面切换时能复用组件实现全局复用池管理 提示 使用 NodePool 管理全局缓存实现 NodeController 包装组件合理控制缓存大小 参考资料 HarmonyOS 官方文档 - 组件复用ArkTS 开发指南 - Reusable 装饰器性能优化最佳实践NodePool 三方库
http://www.ho-use.cn/article/10812385.html

相关文章:

  • 深圳网站设计合理刻罗湖商城网站建设哪家服务周到
  • 西安网站开开发收费网站怎么建立
  • 做网站找不到客户seo网络营销推广公司
  • 天津网站制作公司哪家好wordpress文章多密码
  • 网站开发怎样实现上传视频教程wordpress链接的index.php
  • 长宁区网站制作设计博客做资讯类网站
  • 响应式的网站建设一个多少钱主机装多个wordpress
  • 湖南+网站建设新手怎么开始做微商
  • 企业网站推广的线上渠道有哪些专业的做网站软件
  • 怎么访问域名网站吗电商网站建设哪个好
  • 宜春网站制作wordpress 页面 按钮
  • 网站建设主要用什么软件yeti2.0 wordpress
  • 免费个人网站怎么建立wordpress 翻页效果
  • 手机网站 百度推广成品app直播源码
  • 网站流量如何提高有什么做视频的免费素材网站
  • 某企业网站网页设计模板检测网站开发
  • 全国网站集约化建设试点网站软文制作
  • 单位加强网站建设做网站要学什么知识
  • 服务网站策划书重庆网络学院官网
  • 视频库网站建设漳州市芗城区建设局网站
  • php旅游网站开发小结php做网站答辩问题
  • 备案 非网站备案建站服务器
  • wordpress网站会员太多装修网页设计网站
  • 信誉好的唐山网站建设山东省建筑信息平台
  • 个人网站优秀案例房产网签合同怎么签
  • 北京做网站企业最佳商城ui网站设计
  • 爱站网官网网站内容建设的建议
  • 手机网站的开发wordpress绑定微信公众号
  • 杭州高端定制网站企业网站建设设计服务
  • 宣城市建设监督管理局网站下载网页怎么截图快捷键