鸿蒙开发0基础【wrapBuilder:封装全局@Builder】ArkUI

当开发者在一个struct内使用了多个全局@Builder函数,来实现UI的不同效果时,多个全局@Builder函数会使代码维护起来非常困难,并且页面不整洁。此时,开发者可以使用wrapBuilder来封装全局@Builder。

说明

从API version 11开始使用。

当@Builder方法赋值给变量或者数组后,赋值的变量或者数组在UI方法中无法使用。

@Builder
function builderElement() {}

let builderArr: Function[] = [builderElement];
@Builder
function testBuilder() {
  ForEach(builderArr, (item: Function) => {
    item();
  })
}

在上述代码中,builderArr是一个@Builder方法组成的数组, 在ForEach中取每一项@Builder方法时会出现@Builder方法在UI方法中无法使用的错误。

为了解决这一问题,引入wrapBuilder作为全局@Builder封装函数。wrapBuilder的参数返回WrappedBuilder对象,实现[全局@Builder]可以进行赋值和传递。

接口说明

wrapBuilder是一个模板函数,返回一个WrappedBuilder对象。

declare function wrapBuilder< Args extends Object[]>(builder: (...args: Args) => void): WrappedBuilder;

同时 WrappedBuilder对象也是一个模板类。

declare class WrappedBuilder< Args extends Object[]> {
  builder: (...args: Args) => void;

  constructor(builder: (...args: Args) => void);
}

说明:模板参数Args extends Object[]是需要包装的builder函数的参数列表

使用方法:

let builderVar: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder)
let builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder)] //可以放入数组

限制条件

wrapBuilder方法只能传入[全局@Builder]方法。

wrapBuilder方法返回的WrappedBuilder对象的builder属性方法只能在struct内部使用。

@Builder方法赋值给变量

把@Builder装饰器装饰的方法MyBuilder作为wrapBuilder的参数,再将wrapBuilder赋值给变量globalBuilder,用来解决@Builder方法赋值给变量后无法被使用的问题。

@Builder
function MyBuilder(value: string, size: number) {
  Text(value)
    .fontSize(size)
}

let globalBuilder: WrappedBuilder<[string, number]> = wrapBuilder(MyBuilder);

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  build() {
    Row() {
      Column() {
        globalBuilder.builder(this.message, 50)
      }
      .width('100%')
    }
    .height('100%')
  }
}

@Builder方法赋值给变量在UI语法中使用

自定义组件Index使用ForEach来进行不同@Builder函数的渲染,可以使用builderArr声明的wrapBuilder数组进行不同@Builder函数效果体现。整体代码会较整洁。

@Builder
function MyBuilder(value: string, size: number) {
  Text(value)
    .fontSize(size)
}

@Builder
function YourBuilder(value: string, size: number) {
  Text(value)
    .fontSize(size)
    .fontColor(Color.Pink)
}

const builderArr: WrappedBuilder<[string, number]>[] = [wrapBuilder(MyBuilder), wrapBuilder(YourBuilder)];



@Entry
@Component
struct Index {
  @Builder testBuilder() {
    ForEach(builderArr, (item: WrappedBuilder<[string, number]>) => {
      item.builder('Hello World', 30)
    }

    )
  }

  build() {
    Row() {
      Column() {
        this.testBuilder()
      }
      .width('100%')
    }
    .height('100%')
  }
}

引用传递

通过按引用传递的方式传入参数,会触发UI的刷新。

class Tmp {
  paramA2: string = 'hello';
}

@Builder function overBuilder(param: Tmp) {
  Column(){
    Text(`wrapBuildervalue:${param.paramA2}`)
  }
}

const wBuilder: WrappedBuilder<[Tmp]> = wrapBuilder(overBuilder);

@Entry
@Component
struct Parent{
  @State label: Tmp = new Tmp();
  build(){
    Column(){
      wBuilder.builder({paramA2: this.label.paramA2})
      Button('Click me').onClick(() => {
        this.label.paramA2 = 'ArkUI';
      })
    }
  }
}

常见问题

重复定义wrapBuilder失效

在同一个自定义组件内,同一个wrapBuilder只能初始化一次。示例中builderObj通过wrapBuilder(MyBuilderFirst)初始化定义之后,再次对builderObj进行赋值wrapBuilder(MyBuilderSecond)不会生效。

@Builder
function MyBuilderFirst(value: string, size: number) {
  Text('MyBuilderFirst:' + value)
    .fontSize(size)
}

@Builder
function MyBuilderSecond(value: string, size: number) {
  Text('MyBuilderSecond:' + value)
    .fontSize(size)
}

interface BuilderModel {
  globalBuilder: WrappedBuilder<[string, number]>;
}

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  @State builderObj: BuilderModel = { globalBuilder: wrapBuilder(MyBuilderFirst) };

  aboutToAppear(): void {
    setTimeout(() => {
      // wrapBuilder(MyBuilderSecond) 不会生效
      this.builderObj.globalBuilder = wrapBuilder(MyBuilderSecond);
    },1000)
  }

  build() {
    Row() {
      Column() {
        this.builderObj.globalBuilder.builder(this.message, 20)
      }
      .width('100%')
    }
    .height('100%')
  }
}
### 鸿蒙开发中使用 `@Builder` 注解 #### 示例代码展示 下面是一个具体的例子来说明如何在 HarmonyOS 应用程序中利用 `@Builder` 注解创建自定义组件: ```typescript // 定义带有 @Builder全局函数 @Builder function MyCustomComponent(title: string, contentText: string) { Column() { Text(title).fontSize(50) Divider() Text(contentText).fontColor(Color.Red) .padding({ top: 8 }) } } @Component struct MainAbility { @State titleStr: string = "Hello"; @State contentString: string = "Welcome to the world of HarmonyOS development"; build() { Column() { MyCustomComponent(this.titleStr, this.contentString); }.width('100%') .height('100%') .backgroundColor(Color.White) } } ``` 此段代码展示了怎样通过 `@Builder` 来封装 UI 组件逻辑,使得页面布局更加简洁明了[^2]。 #### 参数传递机制解析 需要注意的是,在调用由 `@Builder` 装饰的方法时,默认情况下参数是以值的方式被复制给目标函数。这意味着如果传入的状态变量发生了变化,则不会触发该方法内部视图的重新渲染。因此建议对于那些可能变动的数据采用引用形式进行传输[^3]。 例如修改上述示例中的 `MyCustomComponent` 函数如下可以实现按引用传递: ```typescript @Builder function MyCustomComponent(@Link title: string, @Link contentText: string) { // 使用 @Link 实现按引用传递 Column() { Text(title).fontSize(50) Divider() Text(contentText).fontColor(Color.Red) .padding({ top: 8 }) } } ``` 这样做的好处在于一旦外部状态发生更新,UI 将会自动同步最新的数据并作出相应调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值