最近看了一下鸿蒙UI范式基本语法文档,又出了一个@LocalBuilder,再加上之前的,这么多Builder相关的装饰器都有什么作用呢,这里就通过一篇文档完全掌握这些装饰器的作用及使用场景。
1.@Builder装饰器:自定义构建函数
- 它是一种轻量级UI复用机制,可将重复使用的UI元素提取到一个方法中,在build方法中调用。
- 我们将@Builder装饰的函数也称之为自定义构建函数。
自定义构建函数有两种使用方式:
-
1.私有自定义构建函数
1.1.私有指函数作用域,仅在组件内部使用。
1.2.自定义组件内定义一个或多个@Builder方法。@Component struct BuilderPage { //私有 自定义构建函数 @Builder customBuilder(){ Text("私有自定义构建函数") } build() { Column(){ this.customBuilder() } } }
-
2.全局自定义构建函数
2.1.如果自定义构建函数中组件不涉及状态变化,建议使用全局的自定义构建方法。
2.2.全局自定义构建函数允许在build方法和其他自定义构建函数中调用。//全局 自定义构建函数 @Builder export function customBuilder(){ Text("全局自定义构建函数") } @Component struct BuilderPage { build() { Column(){ customBuilder() } } }
自定义构建函数参数传递有两种方式:
- 1.按值传递
1.1.调用@Builder装饰的函数默认按值传递
1.2.当传递的参数为状态变量时,状态变量的改变不会引起@Builder方法内的UI刷新。所以当使用状态变量的时候,推荐使用按引用传递。@Component export struct BuilderPage { @State title:string = "张三" //私有 自定义构建函数 @Builder customBuilder(text:string){ Text(text) } build() { Column(){ Text("点击") .onClick(()=>{ this.title = "李四" }) //注意:这里传递的参数为状态变量,当点击按钮时,状态变量的改变不会引起@Builder方法内的UI刷新 this.customBuilder(this.title) } } }
- 2.按引用传递
2.1.传递的参数可为状态变量,且状态变量的改变会引起@Builder方法内的UI刷新。class User{ name:string = "" age:number = 0 } @Component export struct BuilderPage { @State title:string = "张三" @State age:number = 0 //私有 自定义构建函数 按引用传递,这里参数名可以为任意,也可以为$$,看个人喜欢。 @Builder customBuilder($$:User){ Text(`${$$.name} --- ${$$.age}`) } build() { Column(){ Text("点击") .onClick(()=>{ this.title = "李四" this.age = 15 }) //引用方式传递,注意不能直接传递整体对象(该方式无效不显示UI),只能传递其中的属性方式 this.customBuilder({name:this.title,age:this.age}) } } }
注意
- 在自定义构建函数内部,不允许改变参数值。
- 只有传入一个参数,且参数需要直接传入对象字面量才会按引用传递该参数,其余传递方式均为按值传递。**
- 引用传递中对象字面量是指,把所需要的属性一一传入,才会触发动态渲染UI。
2.wrapBuilder:封装全局@Builder
- 它是用于在当组件内使用多个全局的自定义构建函数时,多个全局自定义构建函数维护起来比较困难,可以使用wrapBuilder来封装全局自定义构建函数。
@Entry
@Component
struct BuilderStatePage {
label: string = `Parent`;
@Builder
componentBuilder() {
Text(`componentBuilder---- ${this.label}`)
}
@LocalBuilder
localComponentBuilder() {
Text(`localComponentBuilder---- ${this.label}`)
}
build() {
Column({space: 20}) {
//调用this.componentBuilder()时,this指向当前@Entry所装饰的Parent组件,即label变量的值为"Parent"。
this.componentBuilder()
Child({
// 把this.componentBuilder传给子组件Child的@BuilderParam customBuilderParam,this指向的是子组件Child,即label变量的值为"Child"。
customBuilderParam: this.componentBuilder,
// 把this.localComponentBuilder传给子组件Child的@BuilderParam customLocalBuilderParam,this指向永远是Parent,即label变量的值为"Parent"和传递方式无关。
customLocalBuilderParam: this.localComponentBuilder,
// 把():void=>{this.componentBuilder()}传给子组件Child的@BuilderParam customChangeThisBuilderPara,
// 因为箭头函数的this指向的是宿主对象,所以label变量的值为"Parent"。
customChangeThisBuilderParam: (): void => { this.componentBuilder() }
})
}
.width('100%')
.padding({top:40})
.justifyContent(FlexAlign.Center)
}
}
//子组件
@Component
struct Child {
label: string = `Child`;
@Builder customBuilder() {};
@Builder customLocalBuilder() {};
@Builder customChangeThisBuilder() {};
@BuilderParam customBuilderParam: () => void = this.customBuilder;
@BuilderParam customLocalBuilderParam: () => void = this.customLocalBuilder;
@BuilderParam customChangeThisBuilderParam: () => void = this.customChangeThisBuilder;
build() {
Column({space:20}) {
this.customBuilderParam()
this.customLocalBuilderParam()
this.customChangeThisBuilderParam()
}
}
}
注意:
- 1.wrapBuilder他是鸿蒙中的一个工具方法,将自定义构建函数包裹起来,并返回一个WrappedBuilder对象。
- 2.它只能传递全局的自定义构建函数。
- 3.wrapBuilder的出现主要用于处理多个自定义构建函数的维护问题。
3.@LocalBuilder装饰器:维持组件父子关系
- @Builder + @Builderparams结合使用进行组件间传递自定义构建函数时,传递的方式(普通传递/箭头函数传递)不同而导致this的指向不同。
- @LocalBuilder用于解决传递后,this的指向永远是Parent。
@Entry
@Component
struct BuilderStatePage {
label: string = `Parent`;
@Builder
componentBuilder() {
Text(`componentBuilder---- ${this.label}`)
}
@LocalBuilder
localComponentBuilder() {
Text(`localComponentBuilder---- ${this.label}`)
}
build() {
Column() {
//调用this.componentBuilder()时,this指向当前@Entry所装饰的Parent组件,即label变量的值为"Parent"。
this.componentBuilder()
Child({
// 把this.componentBuilder传给子组件Child的@BuilderParam customBuilderParam,this指向的是子组件Child,即label变量的值为"Child"。
customBuilderParam: this.localComponentBuilder,
// 把():void=>{this.componentBuilder()}传给子组件Child的@BuilderParam customChangeThisBuilderPara,
// 因为箭头函数的this指向的是宿主对象,所以label变量的值为"Parent"。
customChangeThisBuilderParam: (): void => { this.componentBuilder() }
})
}
}
}
//子组件
@Component
struct Child {
label: string = `Child`;
@Builder customBuilder() {};
@Builder customChangeThisBuilder() {};
@BuilderParam customBuilderParam: () => void = this.customBuilder;
@BuilderParam customChangeThisBuilderParam: () => void = this.customChangeThisBuilder;
build() {
Column() {
this.customBuilderParam()
this.customChangeThisBuilderParam()
}
}
}
输出结果:
image.png
总结:
- 当父组件调用子组件,并传递@BuilderParam时分为两种情况
- 传递的是@Builder时,通过this.xxxx进行传递时,此时的this指向的是子组件的Child
- 传递的是@Builder时,通过:()=>{ this.xxxx } 以箭头函数的方式传递时此时的this指向的就是当前的组件Parent
- 当传递的是@LocalBuilder时,通过任何一种方式传递,此时this的指向都是Parent
- 官网说的采用bind(this)的方式是不推荐使用的,编译时会有warning警告,建议采用箭头函数的方式。
- @Builder和@LocalBuilder基本类似,只是传递时this的指向可能不同需要注意。
- @Builder中可以使用另一个@Builder函数,而不能使用@LocalBuilder函数。
- @LocalBuilder中可以使用@Builder函数,也可以使用@LocalBuilder函数。
4.@BuilderParams装饰器:引用@Builder函数
- @BuilderParam为组件增加特定的功能。该装饰器用于声明任意UI描述的一个元素,类似slot占位符。
- @BuilderParam只能被自定义构建函数(@Builder装饰的方法 和 @LocalBuilder装饰的方法)进行初始化。
@Entry
@Component
struct BuilderStatePage {
label: string = `Parent`;
@Builder
componentBuilder() {
Text(`componentBuilder---- ${this.label}`)
this.localComponentBuilder()
}
@LocalBuilder
localComponentBuilder() {
Text(`localComponentBuilder---- ${this.label}`)
}
build() {
Column({space: 20}) {
//调用this.componentBuilder()时,this指向当前@Entry所装饰的Parent组件,即label变量的值为"Parent"。
this.componentBuilder()
Child({
// 把this.componentBuilder传给子组件Child的@BuilderParam customBuilderParam,this指向的是子组件Child,即label变量的值为"Child"。
customBuilderParam: this.componentBuilder,
// 把this.localComponentBuilder传给子组件Child的@BuilderParam customLocalBuilderParam,this指向永远是Parent,即label变量的值为"Parent"和传递方式无关。
customLocalBuilderParam: this.localComponentBuilder,
// 把():void=>{this.componentBuilder()}传给子组件Child的@BuilderParam customChangeThisBuilderPara,
// 因为箭头函数的this指向的是宿主对象,所以label变量的值为"Parent"。
customChangeThisBuilderParam: (): void => { this.componentBuilder() }
})
}
.width('100%')
.padding({top:40})
.justifyContent(FlexAlign.Center)
}
}
//子组件
@Component
struct Child {
label: string = `Child`;
@Builder customBuilder() {};
@Builder customLocalBuilder() {};
@Builder customChangeThisBuilder() {};
@BuilderParam customBuilderParam: () => void = this.customBuilder;
@BuilderParam customLocalBuilderParam: () => void = this.customLocalBuilder;
@BuilderParam customChangeThisBuilderParam: () => void = this.customChangeThisBuilder;
build() {
Column({space:20}) {
this.customBuilderParam()
this.customLocalBuilderParam()
this.customChangeThisBuilderParam()
}
}
}