鸿蒙应用开发UI基础第二十六节:轻量级UI元素@Builder与@LocalBuilder区别示例演示

news2026/3/20 6:52:54
【学习目标】理解 Builder 设计初衷明确与 Component 核心差异掌握 Builder 两种定义方式、参数传递按值/按引用规则掌握 Builder 高级场景嵌套、this指向实战用法掌握 BuilderParam UI 插槽原理与使用方法实现组件 UI 内容灵活定制掌握 LocalBuilder 用法、参数传递与限制理解其固定this、维持组件父子关系的核心特性能够清晰对比 Builder 与 LocalBuilder在实际开发中正确选型。一、Builder 核心认知1.1 什么是 BuilderBuilder用于封装一段UI结构仅负责UI渲染无独立实例、无状态、无生命周期不会加入组件树编译阶段会直接内联展开是组件内/全局复用UI片段的最优轻量方案。1.2 为什么需要 Builder我们已经掌握Component封装可复用UI适用于独立功能、带业务逻辑、带生命周期的页面/组件。但开发中存在大量纯UI结构、无状态、无业务、无生命周期的复用片段例如 列表内固定骨架图页面内重复UI区块。这类片段不需要独立实例、状态、生命周期使用Component会造成额外实例开销粒度过细。因此 ArkTS 提供最轻量UI复用方案Builder 自定义构建函数专注细粒度UI复用几乎无额外性能消耗。1.3 Builder 与 Component 核心区别特性BuilderComponent本质UI构建函数独立自定义组件实例无实例有独立组件实例状态支持不能声明State支持State、Prop等状态生命周期无生命周期拥有完整生命周期调用方式直接调用作为组件使用适用场景纯UI结构复用功能组件/页面/业务模块刷新范围随所属组件整体刷新无独立刷新可独立响应式刷新调用位置只能在build()内部使用任意生命周期与场景均可使用1.4 Builder 两种定义形式组件内 Builder仅当前组件内使用可直接访问组件成员变量与状态跟随组件刷新而刷新全局 Builder整个工程通用不依赖任何组件实例不能访问this所有数据必须通过参数传递。二、项目工程本节工程BuilderDemo基于 API 20所有案例页面完整对应如下BuilderDemo/ ├── AppScope/ ├── entry/ │ ├── src/main/ets │ │ ├── entryability/EntryAbility.ets │ │ ├── pages/ │ │ │ ├── Index.ets # 入口页面跳转 │ │ │ ├── InnerBuilderPage.ets # 组件内Builder │ │ │ ├── GlobalBuilderPage.ets # 全局Builder │ │ │ ├── BuilderParamPage.ets # BuilderParam UI插槽 │ │ │ ├── AdvancedBuilderPage.ets # 高级嵌套、this指向、Binding │ │ │ └── LocalBuilderPage.ets # LocalBuilder 专属案例三、Index.ets 入口页面importrouterfromohos.router;// 定义页面配置接口interfacePageConfig{title:string;url:string;}Entry Component struct Index{pageList:PageConfig[][{title:1. 组件内 Builder,url:pages/InnerBuilderPage},{title:2. 全局 Builder,url:pages/GlobalBuilderPage},{title:3. BuilderParam 插槽,url:pages/BuilderParamPage},{title:4. this指向问题,url:pages/AdvancedBuilderPage},{title:5. LocalBuilder,url:pages/LocalBuilderPage}];// 自定义Builder按钮封装BuilderbuilderButton(title:string,onClick:()void){Button(title).width(280).onClick(onClick);}build(){Column({space:20}){Text(Builder LocalBuilder 实战).fontSize(26).fontWeight(FontWeight.Bold);// ForEach 循环渲染按钮ForEach(this.pageList,(item:PageConfig){this.builderButton(item.title,(){router.pushUrl({url:item.url});});});}.width(100%).height(100%).justifyContent(FlexAlign.Center);}}四、组件内 Builder 示例演示4.1 规则说明组件内 Builder 直接访问 this 状态变量时会跟随组件整体刷新不受传参规则限制自动刷新Builder 默认按值传递参数传递基础类型、对象变量、多参数时外部状态更新不会触发 Builder 刷新Builder 实现响应式刷新的标准方式使用对象字面量形式传入参数可建立响应式关联状态更新自动刷新多层 Builder 嵌套时每一层都必须使用对象字面量传参才能保证全链路刷新禁止在 Builder 内部修改传入的参数对象会导致运行异常从 API version 20 开始可通过 UIUtils.makeBinding()、Binding / MutableBinding 实现 Builder 内状态变量刷新使用 UIUtils.makeBinding() 包装读状态回调支持 Builder 内 UI 自动刷新额外传入写状态回调可将 Builder 内部的参数修改同步到外部组件。4.2 说明Builder被用来展示组件不会参与动态UI刷新。组件中值的变化是通过使用装饰器的特性监听到值的改变触发的UI刷新而不是通过Builder的能力触发的。4.3 示例代码示例 1无参 Builder 直接访问 this → 自动刷新classUserInfo{name:stringage:number0}Entry Component struct InnerBuilderPage{State message:string组件内 Builder 实战State count:number0State user:UserInfo{name:Tom,age:25}BuilderbuildTitle(){Text(this.message).fontSize(24).fontWeight(FontWeight.Bold).fontColor(#333333)}build(){Column({space:15}){this.buildTitle()Button(更新标题).onClick((){this.message组件内 Builder 实战-更新})}.width(100%)}}示例 2按值传递 → 不刷新BuilderbuildButton(label:string){Text(基础类型传参 → 不刷新label)}// 调用this.buildButton(count${this.count})示例 3直接传递对象变量按值传递 → 不刷新BuilderbuildUserCardByObj(params:UserInfo){Text(姓名${params.name}年龄${params.age})}// 调用this.buildUserCardByObj(this.user)示例 4多参数传递按值传递 → 不刷新BuilderbuildUserCardByValue(name:string,age:number){Text(姓名${name}年龄${age})}// 调用this.buildUserCardByValue(this.user.name,this.user.age)示例 5对象字面量 → 按引用传递 → 刷新BuilderbuildUserCardByRef(params:UserInfo){Text(姓名${params.name}年龄${params.age})}// 调用this.buildUserCardByRef({name:this.user.name,age:this.user.age})示例 6嵌套 Builder 子组件刷新对比Component struct ChildComponent1{Prop info:UserInfonewUserInfo();build(){Row(){Text(ChildComponent1不刷新${this.info.name}${this.info.age}).fontSize(20).fontWeight(FontWeight.Bold)}}}Component struct ChildComponent2{Prop childName:string;Prop childAge:number0;build(){Row(){Text(ChildComponent2刷新${this.childName}${this.childAge}).fontSize(20).fontWeight(FontWeight.Bold)}}}BuilderparentBuilder(params:UserInfo){Text(parentBuilder刷新${params.name}${params.age}).fontSize(20).fontWeight(FontWeight.Bold)ChildComponent1({info:params})// 不刷新ChildComponent2({childName:params.name,childAge:params.age})// 刷新}示例 7错误示范Builder 内部修改参数BuildererrorModifyParam(params:UserInfo){Button(修改).onClick((){params.name错误修改// 运行异常})}示例 8API20 新特性 → Binding 绑定传参可修改可刷新BuilderModifyParam(params:BindingUserInfo){Text(姓名${params.value.name})Button(内部修改).onClick((){params.value.name新名字})}// 调用this.ModifyParam(UIUtils.makeBinding(()this.user,(user){this.useruser}))运行结果五、全局 Builder 实战5.1 核心功能定义全局通用UI片段多页面共享无组件依赖不绑定this所有数据必须通过参数传递。5.2 规则必须加function关键字跨页面使用需要加export5.3 示例代码interfaceGlobalInfo{globalContent:string callback?:()void}BuilderexportfunctionglobalButton(globalInfo:GlobalInfo){Button(globalInfo.globalContent).width(180).height(46).backgroundColor(#34C85E).margin(5).onClick(globalInfo?.callback)}BuilderexportfunctionglobalCard(title:string,content:string){Column(){Text(title).fontSize(20).fontWeight(FontWeight.Bold)Text(content).fontSize(16).margin({top:10})}.width(100%).padding(20).backgroundColor(#fff).borderRadius(12).margin(10)}Entry Component struct GlobalBuilderPage{State content:string全局复用跨页面统一样式State globalInfo:GlobalInfo{globalContent:全局按钮1}build(){Column({space:20}){globalCard(全局 Builder 实战,this.content)// 只能通过引用传递 一一传递对应参数 否则无法刷新。globalButton({globalContent:this.globalInfo.globalContent,callback:(){this.globalInfo.globalContent全局按钮点击更新}})}.width(100%).padding(20)}}5.4 运行结果六、BuilderParam UI插槽6.1 核心功能BuilderParam用于接收外部传入的Builder函数实现UI插槽slot能力让组件结构固定、内容可灵活定制。6.2 说明BuilderParam 是组件属性装饰器专门用于接收 Builder 函数类型的参数。使用场景父组件向子组件传递一段UI结构子组件只负责布局不关心具体内容。6.3 示例代码Component struct CardComponent{BuilderParam header?:()voidBuilderParam content?:()voidbuild(){Column(){if(this.header){this.header()}Divider().margin(10).color(Color.Red).strokeWidth(2)if(this.content){this.content()}}.width(100%).backgroundColor(#fff).padding(20).borderRadius(12)}}Entry Component struct BuilderParamPage{BuildercustomHeader(){Text(自定义头部).fontSize(22).fontWeight(FontWeight.Bold)}BuildercustomContent(){Text(这是插槽内容灵活传入任意UI)Button(插槽内按钮).width(150).margin(10)}build(){Column({space:20}){CardComponent({header:this.customHeader,content:this.customContent})}.padding(20)}}6.4 运行结果七、关于this 指向重点我们在使用 Builder BuilderParam 跨组件传递时会出现一个非常关键的问题this 指向会变导致UI刷新不符合预期。7.1 this 指向核心规则Builder 直接作为引用传递时this 由「调用它的组件」决定。箭头函数没有自己的 this会继承外层作用域的 this。在BuilderParam场景直接传递customBuilderParam: this.componentBuilder→ 函数在 Child 里执行this 指向 Child。箭头函数包裹customBuilderParam: () { this.componentBuilder() }→ 继承父组件 thisthis 指向 Parent。7.2 示例代码/** * 问题Builder BuilderParam this 指向问题 * 页面运行结果Parent Child Parent * 核心规则 * 1. 直接传递函数引用 → this 由【调用者】决定 * 2. 箭头函数包裹 → this 继承【定义时的组件】 */Component struct ChildComponent{label:stringChild;// 默认占位Builder无实际UIBuildercustomBuilder(){}BuildercustomChangeThisBuilder(){}// 接收外部传入的Builder函数BuilderParamcustomBuilderParam:()voidthis.customBuilder;BuilderParamcustomChangeThisBuilderParam:()voidthis.customChangeThisBuilder;build(){Row({space:15}){// 执行外部传入的构建函数this.customBuilderParam()this.customChangeThisBuilderParam()}}}Entry Component struct AdvancedBuilderPage{label:stringParent;// 普通 Builderthis 由【运行时调用者】决定不固定BuildercomponentBuilder(){Text(${this.label}).fontSize(26).fontWeight(FontWeight.Bold)}build(){Column({space:20}){Text(运行结果).fontSize(22)Row({space:15}){// 1️⃣ 父组件自己调用 → this 指向Parent → 显示 Parentthis.componentBuilder()ChildComponent({// 2️⃣ 直接传递函数引用函数在子组件内执行 → this 指向Child → 显示 ChildcustomBuilderParam:this.componentBuilder,// 3️⃣ 箭头函数包裹继承父组件this → this 固定指向Parent → 显示 ParentcustomChangeThisBuilderParam:(){this.componentBuilder()}})}}.width(100%).padding(30)}}7.3 运行结果最终页面显示Parent Child Parent7.4 一句话总结this 是函数执行时的上下文对象它的指向不是在函数定义时确定的而是在函数调用时才最终确定。普通函数谁调用this 就指向谁默认规则也是最容易错乱的场景箭头函数没有自己的 this继承外层作用域的 this永远不会错乱优先推荐八、LocalBuilder 装饰器Builder 在跨组件传递时this 会被改变这会导致严重问题UI 刷新不符合预期为了彻底解决这个问题ArkTS提供了LocalBuilder。LocalBuilder可以固定this指向当前8.1 设计目的LocalBuilder 拥有和局部 Builder完全一样的UI构建能力但可以固定 this 指向保证组件父子关系不变保证状态管理父子关系不变从根源解决 Builder 的上下文错乱问题。8.2 核心特性只能在组件内部定义不支持全局this永远指向声明它的组件不会被任何方式改变跨组件传递时组件归属固定不会被修改调用方式与 Builder 完全一致this.xxx()。8.3 LocalBuilder与Builder对比示例Component struct Child{label:stringChild;BuilderParam customBuilderParam?:()void;build(){if(this.customBuilderParam){this.customBuilderParam()}else{Text(BuilderParam undefined)}}}Entry Component struct LocalBuilderPage{label:stringParent;// Builderthis 指向调用方 → ChildBuildercomponentBuilder(){Text(this.label)}// LocalBuilderthis 永远指向 ParentLocalBuildercomponentLocalBuilder(){Text(this.label)}build(){Column({space:20}){// 显示 ChildChild({customBuilderParam:this.componentBuilder})// 显示 ParentChild({customBuilderParam:this.componentLocalBuilder})}}}8.4 限制条件只能在组件内声明不允许全局不能与其他任何装饰器一起使用不能修饰静态方法函数内部不允许修改参数作为参数传递时推荐直接传函数this.func或箭头函数() { this.func() }this指向都不会变.禁止直接传执行结果会导致布局错乱。8.5 参数传递规则与 Builder 一致按值传递基础类型、多参数、直接对象 →不刷新按引用传递单个对象字面量 →可刷新按回调传递API20 使用 UIUtils.makeBinding →可刷新可修改注意子组件调用父组件的 LocalBuilder 并传参时子组件状态变化不会触发LocalBuilder 刷新推荐LocalBuilder 内直接访问父组件自身状态。九、代码仓库工程名称BuilderDemo仓库地址https://gitee.com/HarmonyOS-UI-Basics/harmony-os-ui-basics.git十、下节预告下一节我们将深入学习鸿蒙UI样式复用三大核心方案掌握 Styles 通用样式复用实现多组件基础样式统一掌握 Extend 组件专属样式扩展支持参数与私有属性掌握 stateStyles 多态状态样式实现按压/禁用/选中自动切换清晰区分三者适用场景写出简洁、可维护、高性能样式代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2429061.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…