当前位置:   article > 正文

关于鸿蒙开发中装饰器@Extend、@Styles、@Builder的介绍

关于鸿蒙开发中装饰器@Extend、@Styles、@Builder的介绍

总结

名称适合是否可以参数
@Extend抽取 特定组件 样式、事件
@Styles抽取 公共 样式、事件×
@Builder抽取 结构、样式、事件

@Extend

语法:
@Extend(要扩展的组件,例如TextColumnRow等) function functionName { ... }

使用规则:

1、@Extend仅支持在全局定义,不支持在组件内部定义。

2、@Extend支持封装指定组件的私有属性、私有事件和自身定义的全局方法

  1. // @Extend(Text)可以支持Text的私有属性fontColor
  2. @Extend(Text) function fancy () {
  3. .fontColor(Color.Red)
  4. }
  5. // superFancyText可以调用预定义的fancy
  6. @Extend(Text) function superFancyText(size:number) {
  7. .fontSize(size)
  8. .fancy()
  9. }

3、@Extend装饰的方法支持参数,开发者可以在调用时传递参数,调用遵循TS方法传值调用。

  1. @Extend(Text) function fancy (fontSize: number) {
  2. .fontColor(Color.Red)
  3. .fontSize(fontSize)
  4. }
  5. @Entry
  6. @Component
  7. struct FancyUse {
  8. build() {
  9. Row({ space: 10 }) {
  10. Text('Fancy')
  11. .fancy(16)
  12. Text('Fancy')
  13. .fancy(24)
  14. }
  15. }
  16. }

4、@Extend装饰的方法的参数可以为function,作为Event事件的句柄。 

  1. @Extend(Text) function makeMeClick(onClick: () => void) {
  2. .backgroundColor(Color.Blue)
  3. .onClick(onClick)
  4. }
  5. @Entry
  6. @Component
  7. struct FancyUse {
  8. @State label: string = 'Hello World';
  9. onClickHandler() {
  10. this.label = 'Hello ArkUI';
  11. }
  12. build() {
  13. Row({ space: 10 }) {
  14. Text(`${this.label}`)
  15. .makeMeClick(() => {this.onClickHandler()})
  16. }
  17. }
  18. }

 5、@Extend的参数可以为状态变量,当状态变量改变时,UI可以正常的被刷新渲染。

  1. @Extend(Text) function fancy (fontSize: number) {
  2. .fontColor(Color.Red)
  3. .fontSize(fontSize)
  4. }
  5. @Entry
  6. @Component
  7. struct FancyUse {
  8. @State fontSizeValue: number = 20
  9. build() {
  10. Row({ space: 10 }) {
  11. Text('Fancy')
  12. .fancy(this.fontSizeValue)
  13. .onClick(() => {
  14. this.fontSizeValue = 30
  15. })
  16. }
  17. }
  18. }

使用场景

以下示例声明了3个Text组件,每个Text组件均设置了fontStyle、fontWeight和backgroundColor样式。

  1. @Entry
  2. @Component
  3. struct FancyUse {
  4. @State label: string = 'Hello World'
  5. build() {
  6. Row({ space: 10 }) {
  7. Text(`${this.label}`)
  8. .fontStyle(FontStyle.Italic)
  9. .fontWeight(100)
  10. .backgroundColor(Color.Blue)
  11. Text(`${this.label}`)
  12. .fontStyle(FontStyle.Italic)
  13. .fontWeight(200)
  14. .backgroundColor(Color.Pink)
  15. Text(`${this.label}`)
  16. .fontStyle(FontStyle.Italic)
  17. .fontWeight(300)
  18. .backgroundColor(Color.Orange)
  19. }.margin('20%')
  20. }
  21. }

 @Extend将样式组合复用,示例如下。

  1. @Extend(Text) function fancyText(weightValue: number, color: Color) {
  2. .fontStyle(FontStyle.Italic)
  3. .fontWeight(weightValue)
  4. .backgroundColor(color)
  5. }

通过@Extend组合样式后,使得代码更加简洁,增强可读性。

  1. @Entry
  2. @Component
  3. struct FancyUse {
  4. @State label: string = 'Hello World'
  5. build() {
  6. Row({ space: 10 }) {
  7. Text(`${this.label}`)
  8. .fancyText(100, Color.Blue)
  9. Text(`${this.label}`)
  10. .fancyText(200, Color.Pink)
  11. Text(`${this.label}`)
  12. .fancyText(300, Color.Orange)
  13. }.margin('20%')
  14. }
  15. }

@Styles

说明

1、当前@Styles仅支持通用属性通用事件

2、@Styles可以定义在组件内或全局,在全局定义时需在方法名前面添加function关键字,组件内定义时则不需要添加function关键字。

  1. // 全局
  2. @Styles function functionName() { ... }
  3. // 在组件内
  4. @Component
  5. struct FancyUse {
  6. @Styles fancy() {
  7. .height(100)
  8. }
  9. }

 3、定义在组件内的@Styles可以通过this访问组件的常量和状态变量,并可以在@Styles里通过事件来改变状态变量的值,示例如下:

  1. @Component
  2. struct FancyUse {
  3. @State heightValue: number = 100
  4. @Styles fancy() {
  5. .height(this.heightValue)
  6. .backgroundColor(Color.Yellow)
  7. .onClick(() => {
  8. this.heightValue = 200
  9. })
  10. }
  11. }

4、组件内@Styles的优先级高于全局@Styles。

使用场景

  1. // 定义在全局的@Styles封装的样式
  2. @Styles function globalFancy () {
  3. .width(150)
  4. .height(100)
  5. .backgroundColor(Color.Pink)
  6. }
  7. @Entry
  8. @Component
  9. struct FancyUse {
  10. @State heightValue: number = 100
  11. // 定义在组件内的@Styles封装的样式
  12. @Styles fancy() {
  13. .width(200)
  14. .height(this.heightValue)
  15. .backgroundColor(Color.Yellow)
  16. .onClick(() => {
  17. this.heightValue = 200
  18. })
  19. }
  20. build() {
  21. Column({ space: 10 }) {
  22. // 使用全局的@Styles封装的样式
  23. Text('FancyA')
  24. .globalFancy()
  25. .fontSize(30)
  26. // 使用组件内的@Styles封装的样式
  27. Text('FancyB')
  28. .fancy()
  29. .fontSize(30)
  30. }
  31. }
  32. }

@Builder

限制条件

  • @Builder通过按引用传递的方式传入参数,才会触发动态渲染UI,并且参数只能是一个。

  • @Builder如果传入的参数是两个或两个以上,不会触发动态渲染UI。

  • @Builder传入的参数中同时包含按值传递和按引用传递两种方式,不会触发动态渲染UI。

  • @Builder的参数必须按照对象字面量的形式,把所需要的属性一一传入,才会触发动态渲染UI。

私有自定义构建函数

语法:
@Builder MyBuilderFunction() {}
使用:
this.MyBuilderFunction()

说明:

  • 允许在自定义组件内定义一个或多个@Builder方法,该方法被认为是该组件的私有、特殊类型的成员函数。

  • 自定义构建函数可以在所属组件的build方法和其他自定义构建函数中调用,但不允许在组件外调用。

  • 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不是参数传递。

 全局自定义构建函数

语法:
@Builder function MyGlobalBuilderFunction() { ... }
使用:
MyGlobalBuilderFunction()

说明:

  • 如果不涉及组件状态变化,建议使用全局的自定义构建方法。

参数传递规则

 自定义构建函数测参数传递有 按值传递 和 按引用传递 两种,均需遵守以下规则:

  • 参数的类型必须与参数声明的类型一致,不允许undefined、null和返回undefined、null的表达式。

  • 在@Builder修饰的函数内部,不允许改变参数值。

  • @Builder内UI语法遵循UI语法规则

  • 只有传入一个参数,且参数需要直接传入对象字面量才会按引用传递该参数,其余传递方式均为按值传递。

按引用传递参数

按引用传递参数时,传递的参数可为状态变量,且状态变量的改变会引起@Builder方法内的UI刷新。

  1. class Tmp {
  2. paramA1: string = ''
  3. }
  4. @Builder function overBuilder(params: Tmp) {
  5. Row() {
  6. Text(`UseStateVarByReference: ${params.paramA1} `)
  7. }
  8. }
  9. @Entry
  10. @Component
  11. struct Parent {
  12. @State label: string = 'Hello';
  13. build() {
  14. Column() {
  15. overBuilder({ paramA1: this.label })
  16. Button('Click me').onClick(() => {
  17. this.label = 'ArkUI';
  18. })
  19. }
  20. }
  21. }

按引用传递参数时,如果在@Builder方法内调用自定义组件,ArkUI提供$$作为按引用传递参数的范式。

  1. class Tmp {
  2. paramA1: string = ''
  3. }
  4. @Builder function overBuilder($$: Tmp) {
  5. Row() {
  6. Column() {
  7. Text(`overBuilder===${$$.paramA1}`)
  8. HelloComponent({message: $$.paramA1})
  9. }
  10. }
  11. }
  12. @Component
  13. struct HelloComponent {
  14. @Prop message: string;
  15. build() {
  16. Row() {
  17. Text(`HelloComponent===${this.message}`)
  18. }
  19. }
  20. }
  21. @Entry
  22. @Component
  23. struct Parent {
  24. @State label: string = 'Hello';
  25. build() {
  26. Column() {
  27. overBuilder({paramA1: this.label})
  28. Button('Click me').onClick(() => {
  29. this.label = 'ArkUI';
  30. })
  31. }
  32. }
  33. }

按值传递参数

调用@Builder装饰的函数默认按值传递。当传递的参数为状态变量时,状态变量的改变不会引起@Builder方法内的UI刷新。所以当使用状态变量的时候,推荐使用按引用传递

  1. @Builder function overBuilder(paramA1: string) {
  2. Row() {
  3. Text(`UseStateVarByValue: ${paramA1} `)
  4. }
  5. }
  6. @Entry
  7. @Component
  8. struct Parent {
  9. @State label: string = 'Hello';
  10. build() {
  11. Column() {
  12. overBuilder(this.label)
  13. }
  14. }
  15. }

使用场景

自定义组件内使用自定义构建函数

创建私有的@Builder方法,在Column里面使用this.builder()方式调用,通过aboutToAppear生命周期函数和按钮的点击事件改变builder_value的内容,实现动态渲染UI。

  1. @Entry
  2. @Component
  3. struct PrivateBuilder {
  4. @State builder_value: string = 'Hello';
  5. @Builder builder() {
  6. Column(){
  7. Text(this.builder_value)
  8. .fontSize(30)
  9. .fontWeight(FontWeight.Bold)
  10. }
  11. }
  12. aboutToAppear(): void {
  13. setTimeout(() => {
  14. this.builder_value = 'Hello World';
  15. },3000)
  16. }
  17. build() {
  18. Row() {
  19. Column() {
  20. Text(this.builder_value)
  21. .fontSize(30)
  22. .fontWeight(FontWeight.Bold)
  23. this.builder()
  24. Button('点击改变builder_value内容')
  25. .onClick(() => {
  26. this.builder_value ='builder_value被点击了'
  27. })
  28. }
  29. }
  30. }
  31. }
使用全局自定义构建函数

创建全局的@Builder方法,在Column里面使用overBuilder()方式调用,通过以对象字面量的形式传递参数,无论是简单类型还是复杂类型,值的改变都会引起UI界面的刷新。

  1. class ChildTmp {
  2. val: number = 1;
  3. }
  4. class Tmp {
  5. str_value: string = 'Hello';
  6. num_value: number = 0;
  7. tmp_value: ChildTmp = new ChildTmp();
  8. arrayTmp_value: Array<ChildTmp> = [];
  9. }
  10. @Builder function overBuilder(param: Tmp) {
  11. Column() {
  12. Text(`str_value: ${param.str_value}`)
  13. Text(`num_value: ${param.num_value}`)
  14. Text(`tmp_value: ${param.tmp_value.val}`)
  15. ForEach(param.arrayTmp_value, (item: ChildTmp) => {
  16. Text(`arrayTmp_value: ${item.val}`)
  17. }, (item: ChildTmp) => JSON.stringify(item))
  18. }
  19. }
  20. @Entry
  21. @Component
  22. struct Parent {
  23. @State objParam: Tmp = new Tmp();
  24. build() {
  25. Column() {
  26. Text('通过调用@Builder渲染UI界面')
  27. .fontSize(20)
  28. overBuilder({str_value: this.objParam.str_value, num_value: this.objParam.num_value, tmp_value: this.objParam.tmp_value, arrayTmp_value: this.objParam.arrayTmp_value})
  29. Line()
  30. .width('100%')
  31. .height(10)
  32. .backgroundColor('#000000').margin(10)
  33. Button('点击改变参数值').onClick(() => {
  34. this.objParam.str_value = 'Hello World';
  35. this.objParam.num_value = 1;
  36. this.objParam.tmp_value.val = 8;
  37. const child_value: ChildTmp = {
  38. val: 2
  39. }
  40. this.objParam.arrayTmp_value.push(child_value)
  41. })
  42. }
  43. }
  44. }
修改装饰器修饰的变量触发UI刷新

此种方式是使用了装饰器的特性,监听值的改变触发UI刷新,不通过@Builder传递参数。

  1. class Tmp {
  2. str_value: string = 'Hello';
  3. }
  4. @Entry
  5. @Component
  6. struct Parent {
  7. @State objParam: Tmp = new Tmp();
  8. @State label: string = 'World';
  9. @Builder privateBuilder() {
  10. Column() {
  11. Text(`wrapBuilder str_value: ${this.objParam.str_value}`)
  12. Text(`wrapBuilder num: ${this.label}`)
  13. }
  14. }
  15. build() {
  16. Column() {
  17. Text('通过调用@Builder渲染UI界面')
  18. .fontSize(20)
  19. this.privateBuilder()
  20. Line()
  21. .width('100%')
  22. .height(10)
  23. .backgroundColor('#000000').margin(10)
  24. Button('点击改变参数值').onClick(() => {
  25. this.objParam.str_value = 'str_value Hello World';
  26. this.label = 'label Hello World'
  27. })
  28. }
  29. }
  30. }
使用全局和局部的@Builder传入customBuilder类型
  1. @Builder
  2. function overBuilder() {
  3. Row() {
  4. Text('全局 Builder')
  5. .fontSize(30)
  6. .fontWeight(FontWeight.Bold)
  7. }
  8. }
  9. @Entry
  10. @Component
  11. struct customBuilderDemo {
  12. @State arr: number[] = [0, 1, 2, 3, 4];
  13. @Builder privateBuilder() {
  14. Row() {
  15. Text('局部 Builder')
  16. .fontSize(30)
  17. .fontWeight(FontWeight.Bold)
  18. }
  19. }
  20. build() {
  21. Column() {
  22. List({ space: 10 }) {
  23. ForEach(this.arr, (item: number) => {
  24. ListItem(){
  25. Text(`${item}`)
  26. .width('100%')
  27. .height(100)
  28. .fontSize(16)
  29. .textAlign(TextAlign.Center)
  30. .borderRadius(10)
  31. .backgroundColor(0xFFFFFF)
  32. }
  33. .swipeAction({
  34. start: {
  35. builder: overBuilder()
  36. },
  37. end: {
  38. builder: () => { this.privateBuilder() }
  39. }
  40. })
  41. }, (item: string) => JSON.stringify(item))
  42. }
  43. }
  44. }
  45. }
多层@Builder方法嵌套使用

在@Builder方法内调用自定义组件或者其他@Builder方法,ArkUI提供$$作为按引用传递参数的范式。

  1. class Tmp {
  2. paramA1: string = '';
  3. }
  4. @Builder function parentBuilder($$: Tmp) {
  5. Row() {
  6. Column() {
  7. Text(`parentBuilder===${$$.paramA1}`)
  8. .fontSize(30)
  9. .fontWeight(FontWeight.Bold)
  10. HelloComponent({message: $$.paramA1})
  11. childBuilder({paramA1: $$.paramA1})
  12. }
  13. }
  14. }
  15. @Component
  16. struct HelloComponent {
  17. @Prop message: string = '';
  18. build() {
  19. Row() {
  20. Text(`HelloComponent===${this.message}`)
  21. .fontSize(30)
  22. .fontWeight(FontWeight.Bold)
  23. }
  24. }
  25. }
  26. @Builder
  27. function childBuilder($$: Tmp) {
  28. Row() {
  29. Column() {
  30. Text(`childBuilder===${$$.paramA1}`)
  31. .fontSize(30)
  32. .fontWeight(FontWeight.Bold)
  33. HelloChildComponent({message: $$.paramA1})
  34. grandsonBuilder({paramA1: $$.paramA1})
  35. }
  36. }
  37. }
  38. @Component
  39. struct HelloChildComponent {
  40. @State message: string = '';
  41. build() {
  42. Row() {
  43. Text(`HelloChildComponent===${this.message}`)
  44. .fontSize(30)
  45. .fontWeight(FontWeight.Bold)
  46. }
  47. }
  48. }
  49. @Builder function grandsonBuilder($$: Tmp) {
  50. Row() {
  51. Column() {
  52. Text(`grandsonBuilder===${$$.paramA1}`)
  53. .fontSize(30)
  54. .fontWeight(FontWeight.Bold)
  55. HelloGrandsonComponent({message: $$.paramA1})
  56. }
  57. }
  58. }
  59. @Component
  60. struct HelloGrandsonComponent {
  61. @Prop message: string;
  62. build() {
  63. Row() {
  64. Text(`HelloGrandsonComponent===${this.message}`)
  65. .fontSize(30)
  66. .fontWeight(FontWeight.Bold)
  67. }
  68. }
  69. }
  70. @Entry
  71. @Component
  72. struct Parent {
  73. @State label: string = 'Hello';
  74. build() {
  75. Column() {
  76. parentBuilder({paramA1: this.label})
  77. Button('Click me').onClick(() => {
  78. this.label = 'ArkUI';
  79. })
  80. }
  81. }
  82. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/1005881
推荐阅读
相关标签
  

闽ICP备14008679号