@LocalBuilder装饰器: 维持组件父子关系
一、前言
当开发者使用@Builder做引用数据传递时,会考虑组件的父子关系,使用了bind(this)之后,组件的父子关系和状态管理的父子关系并不一致。为了解决组件的父子关系和状态管理的父子关系保持一致的问题,引入@LocalBuilder装饰器。@LocalBuilder拥有和局部@Builder相同的功能,且比局部@Builder能够更好的确定组件的父子关系和状态管理的父子关系。
在阅读本文档前,建议提前阅读:@Builder。
说明
从API version 12开始支持。
二、装饰器使用说明
2.1 自定义组件内自定义构建函数
定义的语法:
@LocalBuilder MyBuilderFunction() { ... }
使用方法
this.MyBuilderFunction()
- 允许在自定义组件内定义一个或多个@LocalBuilder方法,该方法被认为是该组件的私有、特殊类型的成员函数。
- 自定义构建函数可以在所属组件的build方法和其他自定义构建函数中调用,但不允许在组件外调用。
- 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不是参数传递。
三、限制条件
- @LocalBuilder只能在所属组件内声明,不允许全局声明。
- @LocalBuilder不能被内置装饰器和自定义装饰器使用。
- 自定义组件内的静态方法不能和@LocalBuilder一起使用。
四、@LocalBuilder和局部@Builder使用区别
@Builder方法引用传参时,为了改变this指向,使用bind(this)后,会导致组件的父子关系和状态管理的父子关系不一致,但
@LocalBuilder是否使用bind(this),都不会改变组件的父子关系。@LocalBuilder和@Builder区别说明。
五、参数传递规则
@LocalBuilder函数的参数传递有按值传递和按引用传递两种,均需遵守以下规则:
- 参数的类型必须与参数声明的类型一致,不允许undefined、null和返回undefined、null的表达式。
- 在@LocalBuilder修饰的函数内部,不允许改变参数值。
- @LocalBuilder内UI语法遵循UI语法规则。
- 只有传入一个参数,且参数需要直接传入对象字面量才会按引用传递该参数,其余传递方式均为按值传递。
5.1 按引用传递参数
按引用传递参数时,传递的参数可为状态变量,且状态变量的改变会引起@LocalBuilder方法内的UI刷新。
若子组件调用父组件的@LocalBuilder函数,传入的参数发生变化,不会引起@LocalBuilder方法内的UI刷新。
使用场景:
组件TestLocalBuilder内的@LocalBuilder方法在build函数内调用,按键值对写法进行传值,当点击Click me 时,@LocalBuilder内的Text文本内容会随着状态变量内容的改变而改变。
class ReferenceType {paramString: string = '';
}@Entry
@Component
struct TestLocalBuilder {@State variableValue: string = 'Hello World';@LocalBuilderciteLocalBuilder(params: ReferenceType) {Row() {Text(`UseStateVarByReference: ${params.paramString} `)}};build() {Column({ space: 10 }) {this.citeLocalBuilder({ paramString: this.variableValue });Button('Click me').onClick(() => {this.variableValue = 'Hi World';})}.padding(20)}
}
效果图
按引用传递参数时,如果在@LocalBuilder方法内调用自定义组件,ArkUI提供$$作为按引用传递参数的范式。
使用场景:
组件TestLocalBuilder1内的@LocalBuilder方法内调用自定义组件,且按照引用传递参数将值传递到自定义组件,当Parent组件内状态变量值发生变化时,@LocalBuilder方法内的自定义组件HelloComponent的message值也会发生变化。
class ReferenceType2 {paramString: string = '';
}@Component
struct HelloComponent22 {@Prop message: string;build() {Row() {Text(`HelloComponent===${this.message}`);}}
}@Entry
@Component
struct TestLocalBuilder2 {@State variableValue: string = 'Hello World';@LocalBuilderciteLocalBuilder($$: ReferenceType2) {Row() {Column() {Text(`citeLocalBuilder===${$$.paramString}`);HelloComponent22({ message: $$.paramString });}}}build() {Column({ space: 10 }) {this.citeLocalBuilder({ paramString: this.variableValue });Button('Click me').onClick(() => {this.variableValue = 'Hi World';})}}
}
效果图
子组件引用父组件的@LocalBuilder函数,传入的参数为状态变量,状态变量的改变不会引发@LocalBuilder方法内的UI刷新,原因是@Localbuilder装饰的函数绑定在父组件上,状态变量刷新机制是刷新本组件以及其子组件,对父组件无影响,故无法引发刷新。若使用@Builder修饰则可引发刷新,原因是@Builder改变了函数的this指向,此时函数被绑定到子组件上,故能引发UI刷新。
使用场景:
组件Child将@State修饰的label值按照函数传参方式传递到Parent的@Builder和@LocalBuilder函数内,在被@Builder修饰的函数内,this指向Child,参数变化能引发UI刷新,在被@LocalBuilder修饰的函数内,this指向Parent,参数变化不能引发UI刷新。
class LayoutSize3 {size:number = 0;
}@Entry
@Component
struct TestLocalBuilder3 {label:string = 'parent';@State layoutSize:LayoutSize3 = {size:0};@LocalBuilder// @BuildercomponentBuilder($$:LayoutSize3) {Text(`${'this :'+this.label}`);Text(`${'size :'+$$.size}`);}build() {Column() {Child33({contentBuilder: this.componentBuilder });}}
}@Component
struct Child33 {label:string = 'child';@BuilderParam contentBuilder:((layoutSize: LayoutSize3) => void);@State layoutSize:LayoutSize3 = {size:0};build() {Column() {this.contentBuilder({size: this.layoutSize.size});Button("add child size").onClick(()=>{this.layoutSize.size += 1;})}}
}
效果图
使用@Builder参数变化可以引发UI刷新
六、按值传递参数
调用@LocalBuilder装饰的函数默认按值传递。当传递的参数为状态变量时,状态变量的改变不会引起@LocalBuilder方法内的UI刷新。所以当使用状态变量的时候,推荐使用按引用传递。
使用场景:
组件Parent将@State修饰的label值按照函数传参方式传递到@LocalBuilder函数内,此时@LocalBuilder函数获取到的值为普通变量值,所以改变@State修饰的label值时,@LocalBuilder函数内的值不会发生改变。
@Entry
@Component
struct TestLocalBuilder4 {@State label: string = 'Hello';@LocalBuilderciteLocalBuilder(paramA1: string) {Row() {Text(`UseStateVarByValue: ${paramA1} `)}}build() {Column({space: 10}) {this.citeLocalBuilder(this.label);Button("点击改变@State修饰的label值").onClick(()=>{this.label = "word";console.log(`点击 改变@State修饰的label值 , this.label = ${ this.label}`);})}}
}
效果图
七、@LocalBuilder和@Builder区别说明
函数componentBuilder被@Builder修饰时,显示效果是 “Child”,函数componentBuilder被@LocalBuilder修饰时,显示效果是“Parent”。
说明:
@Builder componentBuilder()通过this.componentBuilder的形式传给子组件@BuilderParam customBuilderParam,this指向在Child的label,即“Child”。
@LocalBuilder componentBuilder()通过this.componentBuilder的形式传给子组件@BuilderParam customBuilderParam,this指向Parent的label,即“Parent”。
@Component
struct Child5 {label: string = `Child5`;@BuilderParam customBuilderParam: () => void;build() {Column() {this.customBuilderParam()}}
}@Entry
@Component
struct TestLocalBuilder5 {label: string = `Parent`;@Builder componentBuilder() {Text(`${this.label}`)}// @LocalBuilder componentBuilder() {// Text(`${this.label}`)// }build() {Column() {Child5({ customBuilderParam: this.componentBuilder })}}
}
函数componentBuilder被@Builder修饰时,显示效果是 “Child”效果图
函数componentBuilder被@LocalBuilder修饰时,显示效果是“Parent”效果图
八、使用场景
@LocalBuilder在@ComponentV2修饰的自定义组件中使用
使用局部的@LocalBuilder在@ComponentV2修饰的自定义组件中调用,修改变量触发UI刷新。
@ObservedV2
class Info6 {@Trace name: string = '';@Trace age: number = 0;
}@ComponentV2
struct ChildPage6 {@Require @Param childInfo: Info6;build() {Column() {Text(`自定义组件 name :${this.childInfo.name}`).fontSize(20).fontWeight(FontWeight.Bold)Text(`自定义组件 age :${this.childInfo.age}`).fontSize(20).fontWeight(FontWeight.Bold)}}
}@Entry
@ComponentV2
struct TestLocalBuilder6 {info1: Info = { name: "Tom", age: 25 };@Local info2: Info = { name: "Tom", age: 25 };@LocalBuilderprivateBuilder() {Column() {Text(`局部LocalBuilder@Builder name :${this.info1.name}`).fontSize(20).fontWeight(FontWeight.Bold)Text(`局部LocalBuilder@Builder age :${this.info1.age}`).fontSize(20).fontWeight(FontWeight.Bold)}}@LocalBuilderprivateBuilderSecond() {Column() {Text(`局部LocalBuilder@Builder name :${this.info2.name}`).fontSize(20).fontWeight(FontWeight.Bold)Text(`局部LocalBuilder@Builder age :${this.info2.age}`).fontSize(20).fontWeight(FontWeight.Bold)}}build() {Column() {Text(`info1: ${this.info1.name} ${this.info1.age}`) // Text1.fontSize(30).fontWeight(FontWeight.Bold)this.privateBuilder() // 调用局部@BuilderLine().width('100%').height(10).backgroundColor('#000000').margin(10)Text(`info2: ${this.info2.name} ${this.info2.age}`) // Text1.fontSize(30).fontWeight(FontWeight.Bold)this.privateBuilderSecond() // 调用局部@BuilderLine().width('100%').height(10).backgroundColor('#000000').margin(10)Text(`info1: ${this.info1.name} ${this.info1.age}`) // Text1.fontSize(30).fontWeight(FontWeight.Bold)ChildPage6({ childInfo: this.info1}) // 调用自定义组件Line().width('100%').height(10).backgroundColor('#000000').margin(10)Text(`info2: ${this.info2.name} ${this.info2.age}`) // Text2.fontSize(30).fontWeight(FontWeight.Bold)ChildPage6({ childInfo: this.info2}) // 调用自定义组件Line().width('100%').height(10).backgroundColor('#000000').margin(10)Button("change info1&info2").onClick(() => {this.info1 = { name: "Cat", age: 18} // Text1不会刷新,原因是没有装饰器修饰监听不到值的改变。this.info2 = { name: "Cat", age: 18} // Text2会刷新,原因是有装饰器修饰,可以监听到值的改变。})}}
}
效果图
相关文章:

@LocalBuilder装饰器: 维持组件父子关系
一、前言 当开发者使用Builder做引用数据传递时,会考虑组件的父子关系,使用了bind(this)之后,组件的父子关系和状态管理的父子关系并不一致。为了解决组件的父子关系和状态管理的父子关系保持一致的问题,引入LocalBuilder装饰器。…...

React(二)——Admin主页/Orders页面/Category页面
文章目录 项目地址一、侧边栏1.1 具体实现 二、Header2.1 实现 三、Orders页面3.1 分页和搜索3.2 点击箭头显示商家所有订单3.3 页码按钮以及分页 四、Category页面4.1 左侧商品添加栏目4.2 右侧商品上传栏 五、Sellers页面六、Payment Request 页面(百万数据加载&a…...

移动端屏幕分辨率rem,less
谷歌模拟器:能直接看到移动端效果 屏幕分辨率 右键电脑桌面 ,点击显示设置 PC端是逻辑分辨率,移动端代码也是参考逻辑分辨率 网页端宽度和逻辑分辨率尺寸相同 手机屏幕尺寸不同,网页宽度均为 100% 所以就需要添加视口标签&#x…...

Docker Desktop 构建java8基础镜像jdk安装配置失效解决
Docker Desktop 构建java8基础镜像jdk安装配置失效解决 文章目录 1.问题2.解决方法3.总结 1.问题 之前的好几篇文章中分享了在Linux(centOs上)和windows10上使用docker和docker Desktop环境构建java8的最小jre基础镜像,前几天我使用Docker Desktop环境重新构建了一个…...

数据结构:栈(Stack)和队列(Queue)—面试题(一)
目录 1、括号匹配 2、逆波兰表达式求值 3、栈的压入、弹出序列 4、最小栈 1、括号匹配 习题链接https://leetcode.cn/problems/valid-parentheses/description/ 描述: 给定一个只包括 (,),{,},[,] …...

AR 眼镜之-拍照/录像动效切换-实现方案
目录 📂 前言 AR 眼镜系统版本 拍照/录像动效切换 1. 🔱 技术方案 1.1 技术方案概述 1.2 实现方案 1)第一阶段动效 2)第二阶段动效 2. 💠 默认代码配置 2.1 XML 初始布局 2.2 监听滑动对 View 改变 3. ⚛️…...

2025年中科院分区大类划分公布!新增8155本
2025年中科院分区表变更情况 扩大收录范围 2025年的期刊分区表在原有的自然科学(SCIE)、社会科学(SSCI)和人文科学(AHCI)的基础上,增加了ESCI期刊的收录,并根据这些期刊的数据进行…...
S变换matlab实现
S变换函数 function [st,t,f] st(timeseries,minfreq,maxfreq,samplingrate,freqsamplingrate) % S变换 % Code by huasir Beijing 2025.1.10 % Reference is "Localization of the Complex Spectrum: The S Transform" % from IEEE Transactions on Signal Proc…...

Springboot——钉钉(站内)实现登录第三方应用
文章目录 前言准备1、创建钉钉应用,并开放网页应用2、配置网页应用各项参数发布版本 前端改造后端逻辑1、获取应用免登录 Access_token2、通过免登录 Access_token 和 Auth_Code 获取对应登录人信息 注意事项 前言 PC端的钉钉中工作台,增加第三方应用&a…...

基于深度学习算法的AI图像视觉检测
基于人工智能和深度学习方法的现代计算机视觉技术在过去10年里取得了显著进展。如今,它被广泛用于图像分类、人脸识别、图像中物体的识别等。那么什么是深度学习?深度学习是如何应用在视觉检测上的呢? 什么是深度学习? 深度学习是…...
cJson——序列化格式json和protobuf对比
cJson——序列化格式json和protobuf对比 1. 更小的消息体积2. 更快的序列化与反序列化速度3. 类型安全4. 向后和向前兼容性5. 更低的带宽消耗6. 高效的编码方式7. 易于跨语言支持8. 支持复杂的数据结构9. 更好的支持大型数据交换总结 Protocol Buffers (Protobuf) 和 JSON 都是…...
搭建一个fastapi的项目,调用ollama服务
1. 项目结构 my_project/ │ ├── app/ │ ├── main.py # FastAPI应用的入口 │ ├── services/ # 包含服务逻辑 │ │ └── ollama_service.py │ ├── models/ # 定义数据模型 │ │ └── response.py │ ├─…...
Wireshark编译手册(Windows)
以下是对 Wireshark 官方文档中“Windows 平台的设置和构建说明”部分的翻译和总结: 2.2. Windows 平台 本节提供了在 Windows 上进行 Wireshark 开发的快速设置指南,包含推荐的配置。 2.2.1. 使用 Microsoft Visual Studio 注意:除非您非…...
在高德地图上加载3DTilesLayer图层模型/天地瓦片
1. 引入必要的库 Three.js:一个用于创建和显示3D图形的JavaScript库。vuemap/three-layer:一个Vue插件,它允许你在高德地图中添加Three.js图层。vuemap/layer-3dtiles:一个用于处理3D Tiles格式数据的Vue插件,可以用来…...

深入浅出负载均衡:理解其原理并选择最适合你的实现方式
负载均衡是一种在多个计算资源(如服务器、CPU核心、网络链接等)之间分配工作负载的技术,旨在优化资源利用率、提高系统吞吐量和降低响应时间。负载均衡的实现方式多种多样,以下是几种常见的实现方式: 1. 硬件负载均衡&…...
STM32的存储结构
STM32F103 芯片是基于 ARM Cortex-M3 内核的微控制器,它集成了多种类型的存储器,每种存储器都有其特定的作用和存储对象。以下是关于 STM32F103 中 Flash、ROM 和 SRAM 的详细介绍: 1. Flash Memory (闪存) 作用:Flash 是非易失性…...
@SneakyThrows 注解详解
SneakyThrows 注解详解 1. 基本介绍 SneakyThrows 是 Lombok 提供的注解,用于简化异常处理,自动生成 try-catch 代码块,将检查型异常转换为非检查型异常。 2. 使用对比 2.1 传统写法 public String readFile(String path) {try {return …...
js监测页面可见性
监测切换页面 检测页面的可见性状态document.visibilityState:document.hiddenvisibilitychange 事件 js 检测页面切换至别的应用 检测页面的可见性状态 在JavaScript中,你可以使用Page Visibility API来检测页面的可见性状态。这个API提供了一组接口,允…...

Android wifi常见问题及分析
参考 Android Network/WiFi 那些事儿 前言 本文将讨论几个有意思的网络问题,同时介绍 Android 上常见WiFi 问题的分析思路。 网络基础Q & A 一. 网络分层缘由 分层想必大家很熟悉,是否想过为何需要这样分层? 网上大多都是介绍每一层…...
EFCore HasDefaultValueSql
今天小伙伴在代码中遇到了有关 HasDefaultValue 的疑问,这里整理澄清下... 在使用 Entity Framework Core (EFCore) 配置实体时,HasDefaultValue 方法会为数据库列设置一个默认值。该默认值的行为取决于以下条件: 1. 配置 HasDefaultValue 的…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...

iview框架主题色的应用
1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题,无需引入,直接可…...

关于easyexcel动态下拉选问题处理
前些日子突然碰到一个问题,说是客户的导入文件模版想支持部分导入内容的下拉选,于是我就找了easyexcel官网寻找解决方案,并没有找到合适的方案,没办法只能自己动手并分享出来,针对Java生成Excel下拉菜单时因选项过多导…...

macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...