鸿蒙开发:了解@Builder装饰器

简介: @Builder装饰是鸿蒙UI开发中,非常重要的一个装饰器,在实际的开发中,合理且正确的使用,能够让我们的代码更加的简洁,有两点需要注意,一是,是用私有还是全局,取决于当前的组件的复用机制,如果多个页面都使用了,建议以全局为主;二是传参的动态更新,有更新就使用引用参数传递,没有更新按值传递即可。

前言

本文代码案例基于Api13,温馨提示:内容相对来说比较简单,如果您已掌握,略过即可。

如果说一个页面中组件有很多,我们都统一写到build函数中,显而易见,会导致build函数代码非常冗余,并且在有相同UI时,也做不到可复用效果,那么,针对这一问题如何解决呢?答案就是抽取出来;在页面内实现UI组件的抽取剥离,其实,在实际的开发中是非常常见的,也就是通过@Builder装饰器来实现。


简单案例


以下是一个多文本展示案例,非常简单,就是几个Text组件,未抽取之前,都统一写在build函数之中。


@Entry
@Component
struct Index {
  build() {
    Column() {
      Text("文本测试一")
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      Text("文本测试二")
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      Text("文本测试三")
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
      Text("文本测试四")
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
    }
    .height('100%')
    .width('100%')
  }
}


使用@Builder装饰器之后:


@Entry
@Component
struct Index {
  @Builder
  textView(text: string) {
    Text(text)
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
  }
  build() {
    Column() {
      this.textView("文本测试一")
      this.textView("文本测试二")
      this.textView("文本测试三")
      this.textView("文本测试四")
    }
    .height('100%')
    .width('100%')
  }
}



显而可见,代码相比未抽取之前,简洁了很多,虽然上述只是一个案例,然而在实际的开发中,页面的复杂程度远远比案例复杂,所以更应该合理的使用@Builder装饰器


什么是@Builder?


在前言中已经明确告知,@Builder它是一个装饰器,主要用于UI元素的复用以及抽取,@Builder所修饰的函数,统称为“自定义构建函数”,可以在函数中定义任何的UI组件,用法和build中的使用是一样的。

使用方式


@Builder装饰器有两种使用方式,一种是定义在UI组件内,也就是上述的使用方式,可以称为私有自定义构建函数,也就是只能给当前的UI组件进行使用,别的UI组件是无法使用的。


与私有自定义构建函数相对应的就是全局自定义构建函数,它可以实现任意的UI组件进行使用,需要用到function关键字,如果定义在非UI组件中,需要用export关键字导出。


我们可以自定义一个扩展类,把共用的组件定义在这里。


@Builder
export function TextView(text: string) {
  Text(text)
    .fontSize(20)
    .fontWeight(FontWeight.Bold)
}


任何一个页面或者UI组件中都可以使用。


import { TextView } from './BuilderView'
@Entry
@Component
struct Index {
  build() {
    Column() {
      TextView("文本测试一")
      TextView("文本测试二")
      TextView("文本测试三")
      TextView("文本测试四")
    }
    .height('100%')
    .width('100%')
  }
}


当然了,如果不是全局共用,仅仅是本页面内共用,也可以使用这种方式来实现。


数据更新


当我们直接更改传递的变量时,会发现@Builder修饰的函数内并没有实现数据改变,如下案例,怎么点击Button都不会发生改变。


@Entry
@Component
struct Index {
  @State testContent: string = "文本测试"
  @Builder
  textView(text: string) {
    Text(text)
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
  }
  build() {
    Column() {
      this.textView(this.testContent)
      Button("改变")
        .margin({ top: 10 })
        .onClick(() => {
          this.testContent = "文本测试2"
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}


这是因为,在@Builder修饰的函数内部,不允许改变参数值,也就是状态变量的改变不会引起@Builder方法内的UI刷新,那么要怎么实现可以动态改变@Builder修饰的函数里的数据呢,有两种方式,一种是,直接把当前的引用也就是当前的类传递过去,直接调用,另一种则是使用引用传递。


this指向当前类


把以上的代码做下更改,由传递值,直接传递当前的类,也就是当前的this,由this直接调用。


@Entry
@Component
struct Index {
  @State testContent: string = "文本测试"
  @Builder
  textView(_this: Index) {
    Text(_this.testContent)
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
  }
  build() {
    Column() {
      this.textView(this)
      Button("改变")
        .margin({ top: 10 })
        .onClick(() => {
          this.testContent = "文本测试2"
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}


可以发现点击Button后,数据实现了动态改变。



按引用传递参数


直接传递当前的this,可以说是最简单的方式,除了这种方式之外,我们还可是使用引用传递参数的方式,动态改变数据,也就是通过传递对象的方式。


class TestBean {
  testContent?: string;
}
@Entry
@Component
struct Index {
  @State testContent: string = "文本测试"
  @Builder
  textView(testBean: TestBean) {
    Text(testBean.testContent)
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
  }
  build() {
    Column() {
      this.textView({ testContent: this.testContent })
      Button("改变")
        .margin({ top: 10 })
        .onClick(() => {
          this.testContent = "文本测试2"
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}


可以看到,以上的数据传递,也能实现数据的动态改变,相对于this传递,使用这种方式则更加灵活,毕竟在实际的开发中,我们可能会遇到多个页面共用组件的情况,传递this显然只适合当前的页面,如果多个页面复用,还是以对象形式传递为佳。


由此可见,在使用@Builder进行参数传递的时候,如果要引起@Builder方法内的UI刷新,可以按照引用传递参数进行实现,按值传递是无法更新UI的。

参数规则


@Builder修饰的函数,其定义的参数类型,必须和传递的类型保持一致,并且不允许undefined、null和返回undefined、null的表达式。

还有一点非常重要,@Builder如果传入的参数是两个或两个以上,不会触发动态渲染UI,比如,上面的案例中,我们随便增加一个参数。

@Builder
  textView(testBean: TestBean, isBoolean: boolean) {
    Text(testBean.testContent)
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
  }

运行后可以发现,数据是无法动态更改的,如果有多个值如何传递呢?两种方式,第一种以this为传递对象,使用this调用更多定义的参数,第二种就是直接定义在对象里,既然都以对象的形式进行传递了,何不都直接定义在对象里呢?

@ComponentV2装饰器更新


使用ComponentV2装饰器,遵循的道理一样,也就是使用简单数据类型不可以触发UI的刷新。


@Entry
@ComponentV2
struct Index {
  @Local testContent: string = "文本测试"
  @Builder
  textView(testContent: string) {
    Column() {
      Text(testContent)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
    }
  }
  build() {
    Column() {
      this.textView(this.testContent)
      Button("改变")
        .margin({ top: 10 })
        .onClick(() => {
          this.testContent = "文本测试2"
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}


如果要更新UI的话,还是需要按引用传递参数,也就是修改为对象传递。


class TestBean {
  testContent?: string;
}
@Entry
@ComponentV2
struct Index {
  @Local testContent: string = "文本测试"
  @Builder
  textView(testBean: TestBean) {
    Column() {
      Text(testBean.testContent)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
    }
  }
  build() {
    Column() {
      this.textView({ testContent: this.testContent })
      Button("改变")
        .margin({ top: 10 })
        .onClick(() => {
          this.testContent = "文本测试2"
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

如果直接以对象的形式传递,不借助成员变量,需要使用@ObservedV2修饰的对象类和@Trace修饰属性才可以触发UI的刷新。

@ObservedV2
class TestBean {
 @Trace testContent: string = "文本测试";
}
@Entry
@ComponentV2
struct Index {
  @Local testBean: TestBean = new TestBean()
  @Builder
  textView(testBean: TestBean) {
    Column() {
      Text(testBean.testContent)
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
    }
  }
  build() {
    Column() {
      this.textView(this.testBean)
      Button("改变")
        .margin({ top: 10 })
        .onClick(() => {
          this.testBean.testContent = "文本测试2"
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}


相关总结


@Builder装饰是鸿蒙UI开发中,非常重要的一个装饰器,在实际的开发中,合理且正确的使用,能够让我们的代码更加的简洁,有两点需要注意,一是,是用私有还是全局,取决于当前的组件的复用机制,如果多个页面都使用了,建议以全局为主;二是传参的动态更新,有更新就使用引用参数传递,没有更新按值传递即可。

相关文章
|
10月前
|
容器
HarmonyOS NEXT仓颉开发语言实战案例:外卖App
仓颉语言实战分享,教你如何用仓颉开发外卖App界面。内容包括页面布局、导航栏自定义、搜索框实现、列表模块构建等,附完整代码示例。轻松掌握Scroll、List等组件使用技巧,提升HarmonyOS应用开发能力。
|
9月前
|
安全 JavaScript API
鸿蒙开发核心要素
鸿蒙开发核心要素
|
6月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1093 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
6月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
850 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
10月前
|
存储 IDE 定位技术
【HarmonyOS 5】鸿蒙组件&模板服务详解 - 助力高效开发的利器
在移动应用开发领域,效率与质量始终是开发者追求的核心目标。鸿蒙系统作为新兴的操作系统,为开发者提供了丰富且强大的开发资源,其中鸿蒙组件&模板服务更是成为开发者快速构建高质量应用的得力助手。
334 0
HarmonyOS NEXT仓颉开发语言实战案例:电影App
周末好!本文分享使用仓颉语言重构ArkTS实现的电影App案例,对比两者在UI布局、组件写法及语法差异。内容包括页面结构、列表分组、分类切换与电影展示等。通过代码演示仓颉在HarmonyOS开发中的应用。##仓颉##ArkTS##HarmonyOS开发
|
10月前
|
容器
HarmonyOS NEXT仓颉开发语言实战案例:健身App
本期分享一个健身App首页的布局实现,顶部采用Stack容器实现重叠背景与偏移效果,列表部分使用List结合Scroll实现可滚动内容。代码结构清晰,适合学习HarmonyOS布局技巧。
HarmonyOS NEXT仓颉开发语言实战案例:小而美的旅行App
本文分享了一个旅行App首页的设计与实现,使用List容器搭配Row、Column布局完成个人信息、功能列表及推荐模块的排版,详细展示了HarmonyOS下的界面构建技巧。
|
6月前
|
移动开发 Rust JavaScript
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
1010 4
【01】首页建立-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
7月前
|
存储 缓存 5G
鸿蒙 HarmonyOS NEXT端云一体化开发-云存储篇
本文介绍用户登录后获取昵称、头像的方法,包括通过云端API和AppStorage两种方式,并实现上传头像至云存储及更新用户信息。同时解决图片缓存问题,添加上传进度提示,支持自动登录判断,提升用户体验。
292 1

热门文章

最新文章

下一篇
开通oss服务