@BuilderParam装饰器的作用,如何使用BuilderParam

背景

开发者创建自定义组件时,常需为组件添加如点击跳转等特定功能。但直接在组件内嵌入事件方法,会使所有使用该组件之处都具备此功能,缺乏灵活性。例如,一个通用的按钮组件,若内置特定点击跳转,在不同页面使用时无法按需定制跳转地址。

ArkUI 的解决方案:@BuilderParam 装饰器

  • 装饰作用:@BuilderParam 用于修饰指向 @Builder 方法的变量,成为 @Builder 函数的承接者。@Builder 方法用于构建 UI 元素或描述 UI 行为逻辑,@BuilderParam 让开发者能灵活控制这些构建逻辑在组件中的应用时机与方式。
  • 传参赋值机制:初始化自定义组件阶段,开发者可借助参数修改、尾随闭包、借用箭头函数等多样方式为被 @BuilderParam 装饰的自定义构建函数传递参数并赋值。以参数修改为例,假设组件用于显示不同文本,可在初始化时将文本内容作为参数传给 @BuilderParam 装饰的函数,从而改变组件显示文本;尾随闭包方式则允许在组件初始化末尾,通过闭包传递复杂逻辑或额外数据;借用箭头函数能简洁地传入动态计算的参数或函数引用。
  • 功能实现路径:在组件内部调用 @BuilderParam,以此为组件动态增添特定功能。如点击跳转场景,组件内点击事件触发时调用 @BuilderParam,执行外部传入的构建函数实现跳转逻辑定制,不同使用场景传入不同跳转函数,满足多样化需求。

类似 slot 占位符的特性

如同 slot 占位符,@BuilderParam 声明 UI 描述元素,预留位置与功能扩展空间。开发者在组件使用处填充内容或逻辑,像 slot 允许父组件向子组件插入内容,@BuilderParam 使外部逻辑注入组件,增强组件复用性与功能扩展性,提升开发效率与代码维护性,构建更灵活、可定制的 UI 组件体系。

下面是使用@BuilderParam需要注意的点

1.使用@BuilderParam装饰器在子组件需要添加默认@Builder

以下是错误示范,不添加默认@Builder

@Entry
@Component
struct father {
  @Builder
  header() {
    Text('header')
      .width('100%')
      .height(50)
      .backgroundColor(Color.Gray)

  }

  @Builder
  body() {
    Text('body')
      .width('100%')
      .height(50)
      .backgroundColor(Color.Pink)

  }

  build() {
    Column() {
      son() {
        this.header()
        this.body()
      }
    }

  }
}

@Component
struct son {
  // @Builder
  // default() {
  // }

  @BuilderParam
  builderParam: () => void  //在这里需要添加默认@Builder的参数

  build() {
    Column() {
      this.builderParam()

    }

  }
}

假设不添加默认@Builder会出现预览器报错,预览器不显示的问题

添加默认@Builder

@Entry
@Component
struct father {
  @Builder
  header() {
    Text('header')
      .width('100%')
      .height(50)
      .backgroundColor(Color.Gray)

  }

  @Builder
  body() {
    Text('body')
      .width('100%')
      .height(50)
      .backgroundColor(Color.Pink)

  }

  build() {
    Column() {
      son() {
        this.header()
        this.body()
      }
    }

  }
}

@Component
struct son {
  @Builder
  default() {
  }

  @BuilderParam
  builderParam: () => void = this.default

  build() {
    Column() {
      this.builderParam()

    }

  }
}

这个时候呢预览器就会正确显示

使用@BuilderParam,是可以使用尾随闭包写法的,但是子组件只允许出现一个@BuilderParam装饰器,不然就会报错,为什么会报错呢,因为有两个@BuilderParam装饰器,父组件尾随闭包写法时,就不知道该传递的是哪一个@BuilderParam修饰的参数

错误写法报错

子组件有两个@BuilderParam参数

@Component
struct son {
  @Builder
  default() {
  }

  @BuilderParam
  builderParam: () => void = this.default
  @BuilderParam
  builderParam2: () => void = this.default

  build() {
    Column() {
      this.builderParam()
      this.builderParam2()

    }

  }
}

父组件尾随闭包写法

@Entry
@Component
struct father {
  @Builder
  header() {
    Text('header')
      .width('100%')
      .height(50)
      .backgroundColor(Color.Gray)

  }

  @Builder
  body() {
    Text('body')
      .width('100%')
      .height(50)
      .backgroundColor(Color.Pink)

  }

  build() {
    Column() {
      son() {
        this.header()
        this.body()
      }
    }

  }
}

报错,不允许尾随闭包写法需要正常父传子写法。

正常父传子写法,就不会报错,预览器正常显示

  build() {
    Column() {
      son({ builderParam: this.header, builderParam2: this.body })
    }

  }
}

关于使用@BuilderParam的this的指向性问题

在父组件和子组件同时使用相同变量名,在给@BuilderParam传递Builder,this是指向父组件和子组件的那个变量呢?首先我们得出结论,this指向子组件变量,因为this指向调用者,牢记this指向调用者

@Entry
@Component
struct father {
  @State
  name: string = '父组件'

  @Builder
  header() {
    Text(this.name)
      .width('100%')
      .height(50)
      .backgroundColor(Color.Gray)

  }

  @Builder
  body() {
    Text(this.name)
      .width('100%')
      .height(50)
      .backgroundColor(Color.Pink)

  }

  build() {
    Column() {
      son({ builderParam: this.header, builderParam2: this.body })
    }

  }
}

@Component
struct son {
  @State name: string = '子组件'

  @Builder
  default() {
  }

  @BuilderParam
  builderParam: () => void = this.default
  @BuilderParam
  builderParam2: () => void = this.default

  build() {
    Column() {
      this.builderParam()    //这里才调用
      this.builderParam2()   //这里才调用

    }

  }
}

this指向子组件

我就想this指向父组件该怎么办呢

我们可以使用回调函数将this指向父组件,以下是示例

@Entry
@Component
struct father {
  @State
  name: string = '父组件'

  @Builder
  header() {
    Text(this.name)
      .width('100%')
      .height(50)
      .backgroundColor(Color.Gray)

  }

  @Builder
  body() {
    Text(this.name)
      .width('100%')
      .height(50)
      .backgroundColor(Color.Pink)

  }

  build() {
    Column() {
      son({
        builderParam: () => {    //回调函数将this指向改变为父组件
          this.header()
        }, builderParam2: () => {
          this.body()
        }
      })
    }

  }
}

总结

当你子组件的参数只有一个BuildrParam才可以使用尾随闭包写法,如果有两个就必须放置builder在大括号里面,没有调用,这个时候会有一个this的指向问题,但是要牢记this指向调用者(子组件),可以使用箭头函数改变this的指向问题,箭头函数的this指向当前组件(父组件),你可能会有疑问,builderParam不是只允许传递builder吗,但是使用箭头函数里面直接调用builder也是属于传递builder(鸿蒙语法是允许的)。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值