HarmonyOS:@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会刷新,原因是有装饰器修饰,可以监听到值的改变。})}}
}

效果图

在这里插入图片描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初学stm32 --- DAC输出三角波和正弦波

输出三角波实验简要: 1,功能描述 通过DAC1通道1(PA4)输出三角波,然后通过DS100示波器查看波形 2,关闭通道1触发(即自动) TEN1位置0 3,关闭输出缓冲 BOFF1位置1 4,使用12位右对齐模式 将数字量写入DAC_…

【opencv】第7章 图像变换

7.1 基 于OpenCV 的 边 缘 检 测 本节中,我们将一起学习OpenCV 中边缘检测的各种算子和滤波器——Canny 算子、Sobel 算 子 、Laplacian 算子以及Scharr 滤波器。 7.1.1 边缘检测的一般步骤 在具体介绍之前,先来一起看看边缘检测的一般步骤。 1.【第…

【Python】Python与C的区别

文章目录 语句结束符代码块表示变量声明函数定义注释格式Python的标识符数据输入input()函数数据输出print()函数 语句结束符 C 语言 C 语言中每条语句必须以分号;结束。例如,int a 10;、printf("Hello, World!");。分号是语句的一部分,用于…

web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理

web-app uniapp监测屏幕大小的变化对数组一行展示数据作相应处理 1.uni.getSystemInfoSync().screenWidth; 获取屏幕宽度 2.uni.onWindowResize() 实时监测屏幕宽度变化 3.根据宽度的大小拿到每行要展示的数量itemsPerRow 4.为了确保样式能够根据 items…

Idea-离线安装SonarLint插件地址

地址: SonarQube for IDE - IntelliJ IDEs Plugin | Marketplace 选择Install Plugin from Disk..,选中下载好的插件,然后重启idea

数据结构与算法之二叉树: LeetCode 637. 二叉树的层平均值 (Ts版)

二叉树的层平均值 https://leetcode.cn/problems/average-of-levels-in-binary-tree/description/ 描述 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值与实际答案相差 1 0 − 5 10^{-5} 10−5 以内的答案可以被接受 示例 1 输入:root…

MySQL表的增删改查(基础)-下篇

修改 真正在改硬盘了,这样的修改是“持久有效”。一定要确保,update的修改是改对了,改出问题来就麻烦。指定update的时候,如果当前不指定任何条件,就会针对所有的行都能生效! (把整个表都给改了)。 案例 --…

项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(五)

文章目录 一、学生管理模块功能实现1、添加学生功能实现1.1 页面设计1.2 前端功能实现1.3 后端功能实现1.4 效果展示2、学生管理功能实现2.1 页面设计2.2 前端功能实现2.3 后端功能实现2.3.1 后端查询接口实现2.3.2 后端编辑接口实现2.3.3 后端删除接口实现2.4 效果展示二、代码…

使用 WPF 和 C# 绘制图形

绘图困难 此示例展示了如何在 WPF 和 C# 中绘制图形。绘制图形总是很棘手,因为您通常需要在至少两个不同的坐标系中工作。首先,您要为图形使用世界坐标。例如,您可能希望 X 值的范围为 2000 年至 2020 年,Y 值的范围为 10,000 美元…

3D滤波器处理遥感tif图像

import cv2 import numpy as np from osgeo import gdal# 定义 Gabor 滤波器的参数 kSize 31 # 滤波器核的大小 g_sigma 3.0 # 高斯包络的标准差 g_theta np.pi / 4 # Gabor 函数的方向 g_lambda 10.0 # 正弦波的波长 g_gamma 0.5 # 空间纵横比 g_psi np.pi / 2 # …

JuiceFS 2024:开源与商业并进,迈向 AI 原生时代

即将过去的 2024 年,是 JuiceFS 开源版本推出的第 4 年,企业版的第 8 个年头。回顾过去这一年,JuiceFS 社区版依旧保持着快速成长的势头,GitHub 星标突破 11.1K,各项使用指标增长均超过 100%,其中文件系统总…

高可用虚拟IP-keepalived

个人觉得华为云这个文档十分详细:使用虚拟IP和Keepalived搭建高可用Web集群_弹性云服务器 ECS_华为云 应用场景:虚拟IP技术。虚拟IP,就是一个未分配给真实主机的IP,也就是说对外提供数据库服务器的主机除了有一个真实IP外还有一个…

支付宝租赁小程序提升租赁行业效率与用户体验

内容概要 在当今数字化的世界里,支付宝租赁小程序的出现构建了一种新的租赁模式,使得用户在使用过程中体验更加流畅。想象一下,你在寻找租赁服务时,不再需要繁琐的流程和冗长的等待,只需通过手机轻松点击几下&#xf…

python异常机制

异常是什么? 软件程序在运行过程中,非常可能遇到刚刚提到的这些问题,我们称之为异常,英文是Exception,意思是例外。遇到这些例外情况,或者交异常,我们怎么让写的程序做出合理的处理&#xff0c…

Git撤销指定commit并更新远端仓库

Git撤销指定commit并更新远端仓库 一、撤销指定commit 1.首先执行git log 命令,查看git历史提交以及commit信息: 由于需要脱敏,所以截图可能看得马赛克比较多,需要关注的就是上面的commit后跟的id,以及HEAD当前指定…

【opencv】第8章 图像轮廓与图像分割修复

8.1 查找并绘制轮廓 一个轮廓一般对应一系列的点,也就是图像中的一条曲线。其表示方法可能 根据不同的情况而有所不同。在OpenCV 中,可以用findContours()函数从二值图 像中查找轮廓 8.1.1 寻找轮廓: findContours() 函数 findContours) 函…

.NET Core NPOI 导出图片到Excel指定单元格并自适应宽度

NPOI:支持xlsx,.xls,版本>2.5.3 XLS:HSSFWorkbook,主要前缀HSS, XLSX:XSSFWorkbook,主要前缀XSS,using NPOI.XSSF.UserModel; 1、导出Excel添加图片效果&#xff0…

SQL分类与数据类型整理

SQL分类与数据类型整理 SQL分类数据类型数值型整数型小数型布尔型字符串型日期型二进制型其他类型(空间数据类型) 总结 SQL,全称为Structured Query Language(结构化查询语言),是一种高度专业化的计算机语言…

基于深度学习算法的AI图像视觉检测

基于人工智能和深度学习方法的现代计算机视觉技术在过去10年里取得了显著进展。如今,它被广泛用于图像分类、人脸识别、图像中物体的识别等。那么什么是深度学习?深度学习是如何应用在视觉检测上的呢? 什么是深度学习? 深度学习是…

30_Redis哨兵模式

在Redis主从复制模式中,因为系统不具备自动恢复的功能,所以当主服务器(master)宕机后,需要手动把一台从服务器(slave)切换为主服务器。在这个过程中,不仅需要人为干预,而且还会造成一段时间内服务器处于不可用状态,同时数据安全性也得不到保障,因此主从模式的可用性…