@Builder装饰器:自定义构建函数
定义:
@Builder是一种轻量的UI复用机制,开发者可以将重复使用的UI元素抽象成一个方法。
简而言之,我们将@Builder装饰的函数也称为“自定义构建函数”。
使用:
@Builder装饰器有两种使用方式,分别是自定义组件内部的私有自定义构建函数和全局自定义构建函数。
例子:
私有自定义构建函数
@Entry
@Component
struct BuilderDemo {
@Builder
showTextBuilder() {
Text('Hello World')
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
@Builder
showTextValueBuilder(param: string) {
Text(param)
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
build() {
Column() {
// 无参数
this.showTextBuilder()
// 有参数
this.showTextValueBuilder('Hello @Builder')
}
}
}
全局自定义构建函数
@Builder
function showTextBuilder() {
Text('Hello World')
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
@Entry
@Component
struct BuilderDemo {
build() {
Column() {
showTextBuilder()
}
}
}
@LocalBuilder装饰器: 维持组件父子关系
定义:
为了解决组件的父子关系和状态管理的父子关系保持一致的问题,引入@LocalBuilder装饰器。@LocalBuilder拥有和局部@Builder相同的功能,且比局部@Builder能够更好的确定组件的父子关系和状态管理的父子关系。
使用:
- 允许在自定义组件内定义一个或多个@LocalBuilder方法,该方法被认为是该组件的私有、特殊类型的成员函数。
- 自定义构建函数可以在所属组件的build方法和其他自定义构建函数中调用,但不允许在组件外调用。
- 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不是参数传递。
限制条件:
- @LocalBuilder只能在所属组件内声明,不允许全局声明。
- @LocalBuilder不能被内置装饰器和自定义装饰器使用。
- 自定义组件内的静态方法不能和@LocalBuilder一起使用。
@LocalBuilder和局部@Builder使用区别
@Builder方法引用传参时,为了改变this指向,使用bind(this)后,会导致组件的父子关系和状态管理的父子关系不一致,使用@LocalBuilder不会改变组件的父子关系。
举例:
class ReferenceType {
paramString: string = '';
}
@Entry
@Component
struct Parent {
@State variableValue: string = 'Hello World';
@LocalBuilder
citeLocalBuilder(params: ReferenceType) {
Row() {
Text(`UseStateVarByReference: ${params.paramString}`)
}
};
build() {
Column() {
this.citeLocalBuilder({ paramString: this.variableValue })
Button('Click me').onClick(() => {
this.variableValue = 'Hi World';
})
}
}
}
@BuilderParam装饰器:引用@Builder函数
定义:
@BuilderParam用来装饰指向@Builder方法的变量。该装饰器用于声明任意UI描述的一个元素,类似slot占位符。
使用:
@Component
struct Child {
@Builder customBuilder() {};
@BuilderParam customBuilderParam: () => void = this.customBuilder;
build() {
Column() {
this.customBuilderParam()
}
}
}
@Preview
@Entry
@Component
struct BuilderParamPage {
@Builder componentBuilder() {
Text(`Parent builder `)
}
build() {
Column() {
Child({ customBuilderParam: this.componentBuilder })
}
}
}
@Styles装饰器:样式复用
使用说明
- 只能在当前文件内使用,不支持export。如果想实现export功能,推荐使用AttributeModifier
// 全局
@Styles function functionName() { ... }
// 在组件内
@Component
struct FancyUse {
@Styles fancy() {
.height(100)
}
}
例子:
// 定义在全局的@Styles封装的样式
@Styles function globalFancy () {
.width(150)
.height(100)
.backgroundColor(Color.Pink)
}
@Entry
@Component
struct FancyUse {
@State heightValue: number = 100;
// 定义在组件内的@Styles封装的样式
@Styles fancy() {
.width(200)
.height(this.heightValue)
.backgroundColor(Color.Yellow)
.onClick(() => {
this.heightValue = 200
})
}
build() {
Column({ space: 10 }) {
// 使用全局的@Styles封装的样式
Text('FancyA')
.globalFancy()
.fontSize(30)
// 使用组件内的@Styles封装的样式
Text('FancyB')
.fancy()
.fontSize(30)
}
}
}
@Extend装饰器:扩展组件样式
@Extend,用于扩展原生组件样式。
限制条件
- 和@Styles不同,@Extend仅支持在全局定义,不支持在组件内部定义。
- 只能在当前文件内使用,不支持export。
@Extend(Text) function fancy (fontSize: number) {
.fontSize(fontSize)
}
@Entry
@Component
struct FancyUse {
build() {
Row({ space: 10 }) {
Text('Fancy')
.fancy(16)
}
}
}
@AnimatableExtend装饰器:定义可动画属性
如果一个属性方法在animation属性前调用,改变这个属性的值可以使animation属性的动画生效,这个属性称为可动画属性。比如height、width、backgroundColor、translate属性,和Text组件的fontSize属性等。
使用说明
@AnimatableExtend(UIComponentName) function functionName(value: typeName) {
.propertyName(value)
}
使用:
@AnimatableExtend(Text)
function animatableWidth(width: number) {
.width(width)
}
@Entry
@Component
struct AnimatablePropertyExample {
@State textWidth: number = 80;
build() {
Column() {
Text("AnimatableProperty")
.animatableWidth(this.textWidth)
.animation({ duration: 2000, curve: Curve.Ease })
Button("Play")
.onClick(() => {
this.textWidth = this.textWidth == 80 ? 160 : 80;
})
}.width("100%")
.padding(10)
}
}
@Require装饰器:校验构造传参
当@Require装饰器和@Prop、@State、@Provide、@BuilderParam、普通变量结合使用时,必须在构造时传参。
举例:
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@Builder buildTest() {
Row() {
Text('Hello, world')
.fontSize(30)
}
}
build() {
Row() {
Child({ regular_value: this.message, state_value: this.message, provide_value: this.message, initMessage: this.message, message: this.message,
buildTest: this.buildTest, initBuildTest: this.buildTest })
}
}
}
@Component
struct Child {
@Builder buildFunction() {
Column() {
Text('initBuilderParam')
.fontSize(30)
}
}
@Require regular_value: string = 'Hello';
@Require @State state_value: string = "Hello";
@Require @Provide provide_value: string = "Hello";
@Require @BuilderParam buildTest: () => void;
@Require @BuilderParam initBuildTest: () => void = this.buildFunction;
@Require @Prop initMessage: string = 'Hello';
@Require @Prop message: string;
build() {
Column() {
Text(this.initMessage)
.fontSize(30)
Text(this.message)
.fontSize(30)
this.initBuildTest();
this.buildTest();
}
.width('100%')
.height('100%')
}
}
@Reusable装饰器:组件复用
@Reusable适用自定义组件,与@Component结合使用,标记为@Reusable的自定义组件从组件树上被移除时,组件和其对应的JSView对象都会被放入复用缓存中,后续创建新自定义组件节点时,会复用缓存区中的节点,节约组件重新创建的时间。
限制条件
- @Reusable装饰器仅用于自定义组件。
- ComponentContent不支持传入@Reusable装饰器装饰的自定义组件。
- @Reusable装饰器不支持嵌套使用,存在增加内存和不方便维护的问题;
使用场景
- 列表滚动:当应用需要展示大量数据的列表,频繁创建和销毁列表项可能导致性能问题。在这种情况下,使用列表组件的组件复用机制可以提高滚动的流畅度。
- 动态布局更新:如果应用中的界面需要频繁地进行布局更新,重复创建和销毁视图可能导致频繁的布局计算,影响帧率。在这种情况下,使用组件复用可以提高性能。
- 频繁创建和销毁数据项的视图场景下。使用组件复用可以重用已创建的视图,只更新数据的内容,减少视图的创建和销毁,能有效提高性能。