(鸿蒙)一篇文档掌握@Builder/wrapBuilder/@LocalBuilder/@BuilderParams

最近看了一下鸿蒙UI范式基本语法文档,又出了一个@LocalBuilder,再加上之前的,这么多Builder相关的装饰器都有什么作用呢,这里就通过一篇文档完全掌握这些装饰器的作用及使用场景。

1.@Builder装饰器:自定义构建函数

  • 它是一种轻量级UI复用机制,可将重复使用的UI元素提取到一个方法中,在build方法中调用。
  • 我们将@Builder装饰的函数也称之为自定义构建函数
自定义构建函数有两种使用方式:
  • 1.私有自定义构建函数
     1.1.私有指函数作用域,仅在组件内部使用。
     1.2.自定义组件内定义一个或多个@Builder方法。

     @Component
     struct BuilderPage {
       //私有 自定义构建函数
       @Builder
       customBuilder(){
         Text("私有自定义构建函数")
       }
    
       build() {
         Column(){
           this.customBuilder()
         }
       }
     }
    
  • 2.全局自定义构建函数
     2.1.如果自定义构建函数中组件不涉及状态变化,建议使用全局的自定义构建方法。
     2.2.全局自定义构建函数允许在build方法其他自定义构建函数中调用。

    //全局 自定义构建函数
    @Builder
    export function customBuilder(){
      Text("全局自定义构建函数")
    }
    
    @Component
    struct BuilderPage {
    
      build() {
        Column(){
          customBuilder()
        }  
      }
    }
    
自定义构建函数参数传递有两种方式:
  • 1.按值传递
     1.1.调用@Builder装饰的函数默认按值传递
     1.2.当传递的参数为状态变量时,状态变量的改变不会引起@Builder方法内的UI刷新。所以当使用状态变量的时候,推荐使用按引用传递
    @Component
    export struct BuilderPage {
       @State title:string = "张三"
    
       //私有 自定义构建函数
       @Builder
       customBuilder(text:string){
          Text(text)
       }
    
       build() {
         Column(){
           Text("点击")
             .onClick(()=>{
                 this.title = "李四"
             })
           //注意:这里传递的参数为状态变量,当点击按钮时,状态变量的改变不会引起@Builder方法内的UI刷新
           this.customBuilder(this.title)
         }
       }
     }
    
  • 2.按引用传递
     2.1.传递的参数可为状态变量,且状态变量的改变会引起@Builder方法内的UI刷新。
    class User{
       name:string = ""
       age:number = 0
    }
    
    @Component
    export struct BuilderPage {
      @State title:string = "张三"
     @State age:number = 0
    
     //私有 自定义构建函数 按引用传递,这里参数名可以为任意,也可以为$$,看个人喜欢。
     @Builder
     customBuilder($$:User){
       Text(`${$$.name} --- ${$$.age}`)
     }
    
     build() {
       Column(){
         Text("点击")
           .onClick(()=>{
             this.title = "李四"
             this.age = 15
           })
    
        //引用方式传递,注意不能直接传递整体对象(该方式无效不显示UI),只能传递其中的属性方式
        this.customBuilder({name:this.title,age:this.age})
       }
     }
    }
    
注意
  • 在自定义构建函数内部,不允许改变参数值。
  • 只有传入一个参数,且参数需要直接传入对象字面量才会按引用传递该参数,其余传递方式均为按值传递。**
  • 引用传递中对象字面量是指,把所需要的属性一一传入,才会触发动态渲染UI。

2.wrapBuilder:封装全局@Builder

  • 它是用于在当组件内使用多个全局的自定义构建函数时,多个全局自定义构建函数维护起来比较困难,可以使用wrapBuilder来封装全局自定义构建函数。
@Entry
@Component
struct BuilderStatePage {
  label: string = `Parent`;

  @Builder
  componentBuilder() {
    Text(`componentBuilder---- ${this.label}`)
  }

  @LocalBuilder
  localComponentBuilder() {
    Text(`localComponentBuilder---- ${this.label}`)
  }

  build() {
    Column({space: 20}) {
      //调用this.componentBuilder()时,this指向当前@Entry所装饰的Parent组件,即label变量的值为"Parent"。
      this.componentBuilder()

      Child({
        // 把this.componentBuilder传给子组件Child的@BuilderParam customBuilderParam,this指向的是子组件Child,即label变量的值为"Child"。
        customBuilderParam: this.componentBuilder,
        // 把this.localComponentBuilder传给子组件Child的@BuilderParam customLocalBuilderParam,this指向永远是Parent,即label变量的值为"Parent"和传递方式无关。
        customLocalBuilderParam: this.localComponentBuilder,
        // 把():void=>{this.componentBuilder()}传给子组件Child的@BuilderParam customChangeThisBuilderPara,
        // 因为箭头函数的this指向的是宿主对象,所以label变量的值为"Parent"。
        customChangeThisBuilderParam: (): void => { this.componentBuilder() }
      })
    }
    .width('100%')
    .padding({top:40})
    .justifyContent(FlexAlign.Center)

  }
}

//子组件
@Component
struct Child {
  label: string = `Child`;

  @Builder customBuilder() {};
  @Builder customLocalBuilder() {};
  @Builder customChangeThisBuilder() {};
  @BuilderParam customBuilderParam: () => void = this.customBuilder;
  @BuilderParam customLocalBuilderParam: () => void = this.customLocalBuilder;
  @BuilderParam customChangeThisBuilderParam: () => void = this.customChangeThisBuilder;

  build() {
    Column({space:20}) {
      this.customBuilderParam()
      this.customLocalBuilderParam()
      this.customChangeThisBuilderParam()
    }
  }
}

注意:

  • 1.wrapBuilder他是鸿蒙中的一个工具方法,将自定义构建函数包裹起来,并返回一个WrappedBuilder对象。
  • 2.它只能传递全局的自定义构建函数。
  • 3.wrapBuilder的出现主要用于处理多个自定义构建函数的维护问题。

3.@LocalBuilder装饰器:维持组件父子关系

  • @Builder + @Builderparams结合使用进行组件间传递自定义构建函数时,传递的方式(普通传递/箭头函数传递)不同而导致this的指向不同。
  • @LocalBuilder用于解决传递后,this的指向永远是Parent。
@Entry
@Component
struct BuilderStatePage {
  label: string = `Parent`;

  @Builder
  componentBuilder() {
    Text(`componentBuilder---- ${this.label}`)
  }

  @LocalBuilder
  localComponentBuilder() {
    Text(`localComponentBuilder---- ${this.label}`)
  }

  build() {
    Column() {
      //调用this.componentBuilder()时,this指向当前@Entry所装饰的Parent组件,即label变量的值为"Parent"。
      this.componentBuilder()

      Child({
        // 把this.componentBuilder传给子组件Child的@BuilderParam customBuilderParam,this指向的是子组件Child,即label变量的值为"Child"。
        customBuilderParam: this.localComponentBuilder,
        // 把():void=>{this.componentBuilder()}传给子组件Child的@BuilderParam customChangeThisBuilderPara,
        // 因为箭头函数的this指向的是宿主对象,所以label变量的值为"Parent"。
        customChangeThisBuilderParam: (): void => { this.componentBuilder() }
      })
    }
  }
}

//子组件
@Component
struct Child {
  label: string = `Child`;
  
  @Builder customBuilder() {};
  @Builder customChangeThisBuilder() {};
  @BuilderParam customBuilderParam: () => void = this.customBuilder;
  @BuilderParam customChangeThisBuilderParam: () => void = this.customChangeThisBuilder;

  build() {
    Column() {
      this.customBuilderParam()
      this.customChangeThisBuilderParam()
    }
  }
}
输出结果:
image.png
总结:
  1. 当父组件调用子组件,并传递@BuilderParam时分为两种情况
  2. 传递的是@Builder时,通过this.xxxx进行传递时,此时的this指向的是子组件的Child
  3. 传递的是@Builder时,通过:()=>{ this.xxxx } 以箭头函数的方式传递时此时的this指向的就是当前的组件Parent
  4. 当传递的是@LocalBuilder时,通过任何一种方式传递,此时this的指向都是Parent
  5. 官网说的采用bind(this)的方式是不推荐使用的,编译时会有warning警告,建议采用箭头函数的方式。
  6. @Builder和@LocalBuilder基本类似,只是传递时this的指向可能不同需要注意。
  7. @Builder中可以使用另一个@Builder函数,而不能使用@LocalBuilder函数。
  8. @LocalBuilder中可以使用@Builder函数,也可以使用@LocalBuilder函数。

4.@BuilderParams装饰器:引用@Builder函数

  • @BuilderParam为组件增加特定的功能。该装饰器用于声明任意UI描述的一个元素,类似slot占位符。
  • @BuilderParam只能被自定义构建函数(@Builder装饰的方法 和 @LocalBuilder装饰的方法)进行初始化。
@Entry
@Component
struct BuilderStatePage {
  label: string = `Parent`;

  @Builder
  componentBuilder() {
    Text(`componentBuilder---- ${this.label}`)
    this.localComponentBuilder()
  }

  @LocalBuilder
  localComponentBuilder() {
    Text(`localComponentBuilder---- ${this.label}`)
  }

  build() {
    Column({space: 20}) {
      //调用this.componentBuilder()时,this指向当前@Entry所装饰的Parent组件,即label变量的值为"Parent"。
      this.componentBuilder()

      Child({
        // 把this.componentBuilder传给子组件Child的@BuilderParam customBuilderParam,this指向的是子组件Child,即label变量的值为"Child"。
        customBuilderParam: this.componentBuilder,
        // 把this.localComponentBuilder传给子组件Child的@BuilderParam customLocalBuilderParam,this指向永远是Parent,即label变量的值为"Parent"和传递方式无关。
        customLocalBuilderParam: this.localComponentBuilder,
        // 把():void=>{this.componentBuilder()}传给子组件Child的@BuilderParam customChangeThisBuilderPara,
        // 因为箭头函数的this指向的是宿主对象,所以label变量的值为"Parent"。
        customChangeThisBuilderParam: (): void => { this.componentBuilder() }
      })
    }
    .width('100%')
    .padding({top:40})
    .justifyContent(FlexAlign.Center)

  }
}

//子组件
@Component
struct Child {
  label: string = `Child`;

  @Builder customBuilder() {};
  @Builder customLocalBuilder() {};
  @Builder customChangeThisBuilder() {};
  @BuilderParam customBuilderParam: () => void = this.customBuilder;
  @BuilderParam customLocalBuilderParam: () => void = this.customLocalBuilder;
  @BuilderParam customChangeThisBuilderParam: () => void = this.customChangeThisBuilder;

  build() {
    Column({space:20}) {
      this.customBuilderParam()
      this.customLocalBuilderParam()
      this.customChangeThisBuilderParam()
    }
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容