ArkUI开发进阶—@Builder函数@BuilderParam装饰器的妙用与场景应用
HarmonyOS,作为一款全场景分布式操作系统,为了推动更广泛的应用开发,采用了一种先进而灵活的编程语言——ArkTS。ArkTS是在TypeScript(TS)的基础上发展而来,为HarmonyOS提供了丰富的应用开发工具,使开发者能够更轻松地构建出色的多设备应用。
ArkTS的基础:TypeScript的超集
在深入ArkTS之前,了解其基础是至关重要的。ArkTS是TypeScript的超集,继承了TS的所有特性,因此,对于已经熟悉TS的开发者而言,学习ArkTS将变得更加顺利。这种扩展使得ArkTS具备更丰富的语法和功能,为HarmonyOS应用提供了更大的灵活性。
ArkTS的核心能力扩展
1. 基本语法扩展
ArkTS不仅仅是在语法上对TypeScript的简单包装,它在基本语法上进行了进一步的扩展。通过引入声明式UI描述、自定义组件和动态扩展UI元素的能力,ArkTS为UI开发提供了更直观且高效的工具。这与ArkUI框架中的系统组件、事件方法以及属性方法相互配合,构建了应用开发的主体。
2. 状态管理机制
在应用开发中,状态管理是一个关键的问题。ArkTS引入了多维度的状态管理机制,使得与UI相关的数据可以在组件内使用,也可以在不同组件层级间传递。这种多层级的状态管理不仅包括父子组件之间的传递,还支持应用全局范围内的数据传递和跨设备传递。开发者可以根据需求选择只读的单向传递或可变更的双向传递,实现数据和UI的灵活联动。
3. 渲染控制
ArkTS提供了灵活的渲染控制能力,包括条件渲染、循环渲染和数据懒加载。条件渲染使得应用能够根据不同状态渲染相应的UI内容,而循环渲染则允许从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件。数据懒加载则按需迭代数据,实现更高效的应用性能。
ArkTS基本语法概述
为了更好地理解ArkTS的基本组成,我们将通过一个简单的示例来演示其语法和结构。
示例:Hello ArkUI
// 使用装饰器定义组件和状态
@Entry
@Component
struct Hello {
@State myText: string = 'Hello World';
// 声明UI结构
build() {
Column() {
Text(this.myText)
.fontSize(20)
Button('Click me')
.onClick(() => {
this.myText = 'Hello ArkUI';
})
}
}
}
在这个示例中,我们使用了装饰器@Entry、@Component、@State,定义了一个名为Hello的组件,并声明了一个状态变量myText。在UI结构的描述中,我们使用了Column、Text和Button等系统组件,以及相应的属性方法和事件方法。
这个简单的示例展示了ArkTS的基本组成,包括装饰器、声明式UI描述、自定义组件、系统组件、属性方法和事件方法的使用。
ArkTS的高级语法范式
除了基本语法外,ArkTS还扩展了多种高级语法范式,使得开发变得更加便捷和灵活。
1. @Builder/@BuilderParam
这是一种特殊的封装UI描述的方法,可以实现细粒度的封装和复用UI描述。
2. @Extend/@Style
通过@Extend和@Style,开发者可以扩展内置组件和封装属性样式,更灵活地组合内置组件。
3. stateStyles
这是一种多态样式的应用,可以根据组件的内部状态的不同,设置不同的样式。
使用 @Builder 自定义构建函数
进一步理解 @Builder 装饰器
在前文示例中,我们已经展示了如何在组件内使用 @Builder
装饰器创建自定义构建函数,并在组件的 build
方法中调用该函数,实现了对按钮的定制。接下来,我们将深入理解 @Builder 装饰器的一些重要概念。
1. 构建函数内部的 this 指向
在自定义构建函数内部,this
关键字指向当前所属组件。这意味着你可以访问和操作组件内的状态变量。让我们通过一个例子来说明:
@Entry
@Component
struct ExampleComponent {
@State buttonText: string = 'Click me';
@Builder
BuildButton() {
Button(this.buttonText)
.onClick(() => {
console.log(`Button Clicked! Current text: ${this.buttonText}`);
});
}
build() {
Column() {
Text('Welcome to ArkTS!')
.fontSize(20)
// 调用自定义构建函数
this.BuildButton()
}
}
}
在这个例子中,我们在构建函数的点击事件处理中使用了 this.buttonText
,这样就能在点击按钮时打印出当前按钮文本的信息。
2. 构建函数的参数传递
通过 @Builder
装饰器创建的构建函数支持参数传递。参数的传递可以是按值传递或按引用传递。在前文的说明中,我们已经了解了这两种传递方式的使用规则。
@Builder MyBuilderFunction(param: string) {
// 构建函数体
}
通过参数传递,你可以将外部数据灵活地传递给自定义构建函数,实现更加通用和可配置的构建逻辑。
3. 全局自定义构建函数
除了在组件内定义自定义构建函数,你还可以创建全局自定义构建函数。全局构建函数不属于任何特定组件,因此不能使用 this
关键字,也不能访问组件内的状态变量。这适用于那些与组件无关的通用构建逻辑。
@Builder
function GlobalBuilderFunction() {
// 全局构建函数体
}
在应用的任何地方都可以调用全局构建函数,实现全局范围内的构建逻辑复用。
最佳实践与建议
-
合理使用参数传递: 在使用
@Builder
装饰器时,根据实际需求选择合适的参数传递方式。按值传递适用于不需要响应外部变化的场景,而按引用传递适用于需要响应外部变化的场景。 -
充分利用 this 指向: 在自定义构建函数内部,充分利用
this
指向,访问和操作组件内的状态变量,实现更灵活的构建逻辑。 -
全局构建函数的谨慎使用: 全局构建函数适用于通用逻辑,但在使用时要谨慎,确保其不依赖于特定组件的状态或上下文。
-
构建函数的命名规范: 为了提高代码的可读性,建议根据构建函数的功能给予清晰的命名,使其用途一目了然。
@BuilderParam装饰器:引用@Builder函数
在ArkUI中,当开发者创建自定义组件时,有时希望对组件添加特定的功能,例如在自定义组件中添加一个点击跳转操作。直接在组件内嵌入事件方法可能导致所有引入该自定义组件的地方都增加了该功能。为解决这个问题,ArkUI引入了@BuilderParam
装饰器。@BuilderParam
用来装饰指向@Builder
方法的变量,开发者可以在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。该装饰器类似于一个占位符,用于声明任意UI描述的一个元素。
说明
从API version 9开始,该装饰器支持在ArkTS卡片中使用。
装饰器使用说明
初始化@BuilderParam装饰的方法
@BuilderParam
装饰的方法只能被自定义构建函数(@Builder
装饰的方法)初始化。
- 使用所属自定义组件的自定义构建函数或全局的自定义构建函数,在本地初始化@BuilderParam。
@Builder function GlobalBuilder0() {}
@Component
struct Child {
@Builder doNothingBuilder() {};
@BuilderParam aBuilder0: () => void = this.doNothingBuilder;
@BuilderParam aBuilder1: () => void = GlobalBuilder0;
build(){}
}
- 用父组件自定义构建函数初始化子组件@BuilderParam装饰的方法。
@Component
struct Child {
@BuilderParam aBuilder0: () => void;
build() {
Column() {
this.aBuilder0()
}
}
}
@Entry
@Component
struct Parent {
@Builder componentBuilder() {
Text(`Parent builder `)
}
build() {
Column() {
Child({ aBuilder0: this.componentBuilder })
}
}
}
注意: 在这个例子中,当父组件的构建函数 componentBuilder
传递给子组件的 aBuilder0
时,this
指向正确,即指向父组件。
@Component
struct Child {
label: string = `Child`
@BuilderParam aBuilder0: () => void;
build() {
Column() {
this.aBuilder0()
}
}
}
@Entry
@Component
struct Parent {
label: string = `Parent`
@Builder componentBuilder() {
Text(`${this.label}`)
}
build() {
Column() {
this.componentBuilder()
Child({ aBuilder0: this.componentBuilder })
}
}
}
使用场景
1. 参数初始化组件
@BuilderParam
装饰的方法可以是有参数和无参数的两种形式,需要与指向的@Builder
方法类型匹配。
@Builder function GlobalBuilder1($$ : {label: string }) {
Text($$.label)
.width(400)
.height(50)
.backgroundColor(Color.Blue)
}
@Component
struct Child {
label: string = 'Child'
// 无参数类,指向的componentBuilder也是无参数类型
@BuilderParam aBuilder0: () => void;
// 有参数类型,指向的GlobalBuilder1也是有参数类型的方法
@BuilderParam aBuilder1: ($$ : { label : string}) => void;
build() {
Column() {
this.aBuilder0()
this.aBuilder1({label: 'global Builder label' } )
}
}
}
@Entry
@Component
struct Parent {
label: string = 'Parent'
@Builder componentBuilder() {
Text(`${this.label}`)
}
build() {
Column() {
this.componentBuilder()
Child({ aBuilder0: this.componentBuilder, aBuilder1: GlobalBuilder1 })
}
}
}
2. 尾随闭包初始化组件
在自定义组件中使用@BuilderParam
装饰的属性时,也可以通过尾随闭包进行初始化。在初始化自定义组件时,组件后紧跟一个大括号“{}”形成尾随闭包场景。
// xxx.ets
@Component
struct CustomContainer {
@Prop header: string;
@BuilderParam closer: () => void
build() {
Column
() {
Text(this.header)
.fontSize(30)
this.closer()
}
}
}
@Builder function specificParam(label1: string, label2: string) {
Column() {
Text(label1)
.fontSize(30)
Text(label2)
.fontSize(30)
}
}
@Entry
@Component
struct CustomContainerUser {
@State text: string = 'header';
build() {
Column() {
// 创建CustomContainer,在创建CustomContainer时,通过其后紧跟一个大括号“{}”形成尾随闭包
// 作为传递给子组件CustomContainer @BuilderParam closer: () => void的参数
CustomContainer({ header: this.text }) {
Column() {
specificParam('testA', 'testB')
}.backgroundColor(Color.Yellow)
.onClick(() => {
this.text = 'changeHeader';
})
}
}
}
}
通过不同的初始化方式和使用场景,开发者可以更好地掌握 @BuilderParam
装饰器的使用方法,提高代码的可读性和可维护性。
未来展望
ArkTS作为HarmonyOS应用开发的主力语言,未来将持续演进。计划逐步提供并行和并发能力增强、系统类型增强、分布式开发范式等更多特性,以满足不断变化的应用开发需求。
结语
通过深入理解 @Builder
装饰器,我们可以更好地使用自定义构建函数来实现 UI 元素的复用,提高代码的可维护性和可读性。这一特性使得 ArkTS 在应用开发中更加灵活,让开发者能够更轻松地构建复杂的用户界面。在实际应用中,合理使用 @Builder
装饰器将为项目带来更多的便利。