当前位置:   article > 正文

【鸿蒙HarmonyOS开发笔记】组件编程技巧之使用@Builder装饰器实现UI结构复用_鸿蒙 @builder

鸿蒙 @builder

概述

当页面有多个相同的UI结构时,若每个都单独声明,同样会有大量重复的代码。为避免重复代码,可以将相同的UI结构提炼为一个自定义组件,完成UI结构的复用。

除此之外,ArkTS还提供了一种更轻量的UI结构复用机制@Builder方法,开发者可以将重复使用的UI元素抽象成一个@Builder方法,该方法可在build()方法中调用多次,以完成UI结构的复用。


语法说明

@Builder方法同样可以定义在组件内或者全局,具体语法如下

● 组件内

@Entry
@Component
struct BuilderPage {
  build() {
    Column() {
      Row({ space: 50 }) {
        //复用UI结构
        this.compButtonBuilder($r('app.media.icon_edit'), '编辑', () => console.log('编辑'))
        this.compButtonBuilder($r('app.media.icon_send'), '发送', () => console.log('发送'))
      }
    }.width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  //定义UI结构
  @Builder compButtonBuilder(icon: Resource, text: string, callback: () => void) {
    Button() {
      Row({ space: 10 }) {
        Image(icon)
          .width(25)
          .height(25)
        Text(text)
          .fontColor(Color.White)
          .fontSize(25)
      }
    }.width(120)
    .height(50)
    .onClick(callback)
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

● 全局

@Entry
@Component
struct BuilderPage {
  build() {
    Column() {
      Row({ space: 50 }) {
        //复用UI结构
        globalButtonBuilder($r('app.media.icon_edit'), '编辑', () => console.log('编辑'))
        globalButtonBuilder($r('app.media.icon_send'), '发送', () => console.log('发送'))
      }
    }.width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

//定义UI结构
@Builder function globalButtonBuilder(icon: Resource, text: string, callback: () => void) {
    Button() {
      Row({ space: 10 }) {
        Image(icon)
          .width(25)
          .height(25)
        Text(text)
          .fontColor(Color.White)
          .fontSize(25)
      }
    }.width(120)
    .height(50)
    .onClick(callback)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

注意

  1. 组件内的@Builder方法可通过this访问当前组件的属性和方法,而全局的@Builder方法则不能
  2. 组件内的@Builder方法只能用于当前组件,全局的@Builder方法导出(export)后,可用于整个应用。

@Builder方法参数传递规则

@Builder方法具有两种参数传递机制——按值传递按引用传递。当只有一个参数且参数为对象字面量时为按引用传递,其余情况均为按值传递。

按引用传递时,若传递的参数为状态变量,则状态变量的变化将会触发@Builder方法内部UI的刷新;按值传递时则不会。

@Entry
@Component
struct BuilderParameterPage {
  @State count: number = 0;

  build() {
    Column({ space: 50 }) {
      //按值传递
      valueTextBuilder(this.count)
      //按引用传递
      referenceTextBuilder({ count: this.count })
      Row({ space: 50 }) {
        Button('-1').onClick(() => {
          this.count--;
        })
        Button('+1').onClick(() => {
          this.count++;
        })
      }
    }.width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

@Builder function valueTextBuilder(count: number) {
  Text(`按值传递: ${count}`)
    .fontSize(30)
    .fontWeight(FontWeight.Bold)
}

@Builder function referenceTextBuilder(obj: { count: number }) {
  Text(`按引用传递: ${obj.count}`)
    .fontSize(30)
    .fontWeight(FontWeight.Bold)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

@Builder方法和自定义组件的区别

@Builder方法和自定义组件虽然都可以实现UI复用的效果,但是两者还是有着本质的区别的,其中最为显著的一个区别就是自定义组件可以定义自己的状态变量,而@Builder方法则不能。

以下案例中,每个待办事项的UI结构都相同,因此可考虑将其提炼为一个自定义组件或者@Builder方法,但是由于每个待办事项均有已完成未完成两种状态,因此需要为每个待办事项都定义一个状态变量,所以此时就只能使用自定义组件而不能使用@Builder方法。

在这里插入图片描述

总结

若复用的UI结构没有状态,推荐使用@Builder方法,否则使用自定义组件。


@BuilderParam

@BuilderParam用于装饰自定义组件(struct)中的属性,其装饰的属性可作为一个UI结构的占位符,待创建该组件时,可通过参数为其传入具体的内容。(其作用类似于Vue框架中的slot)。

例如

定义一个组件,使用@BuilderParam占位

@Component
struct Container {
   //@BuilderParam属性
  @BuilderParam content: () => void

  build() {
    Column() {
      Text('其他内容') //其他内容
      this.content(); //占位符
      Button('其他内容') //其他内容
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

定义UI结构

@Builder function contentBuilder1() {
  ...
}

@Builder function contentBuilder2() {
  ...
}

@Builder function contentBuilder3() {
  ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

组件创建时可传入不同的UI来填充

Container({ content: contentBuilder1 })

Container({ content: contentBuilder2 })

Container({ content: contentBuilder3 })
  • 1
  • 2
  • 3
  • 4
  • 5

另外,如果一个组件中只定义了一个@BuilderParam属性,那么创建该组件时,也可直接通过"子组件"的方式传入具体的UI结构,例如

@Entry
@Component
struct BuilderParamPage {
  build() {
    Column({ space: 50 }) {
      //创建卡片组件(传参)
      Card({ content: imageBuilder })

      //创建卡片组件("子组件")
      Card() {
        Column({ space: 10 }) {
          Text('鸿蒙操作系统')
            .fontSize(25)
            .fontWeight(FontWeight.Bold)
          Text('鸿蒙操作系统是一款由华为公司开发的多设备统一操作系统,致力于实现无缝连接和协同工作。其采用分布式架构,支持多终端智能互联,提供高效、安全、流畅的用户体验。')
        }
      }
    }.width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

//卡片内容
@Builder function imageBuilder() {
  Column({ space: 10 }) {
    Image($r('app.media.img_harmony'))
      .width(300)
      .height(150)
    Text('鸿蒙操作系统')
  }
}

//卡片组件
@Component
struct Card {
  @BuilderParam content: () => void; //@BuilderParam属性

  build() {
    Column() {
      this.content(); //占位符
    }.width('90%')
    .padding(10)
    .borderRadius(10)
    .shadow({ radius: 20 })
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/573147
推荐阅读
相关标签
  

闽ICP备14008679号