HarmonyOS第五章:组件抽取、构建函数抽取@Builder、构建函数插槽@BuilderParam

🎉 博客主页:【剑九_六千里-CSDN博客】【剑九_六千里-掘金社区

🎨 上一篇文章:【HarmonyOS第四章:样式操作及渲染页面

🎠 系列专栏:【HarmonyOS系列

💖 感谢大家点赞👍收藏⭐评论✍

文章目录

  • [1. 组件化抽取](#1. 组件化抽取)
    • [1.1. 组件拆分及导入导出](#1.1. 组件拆分及导入导出)
  • [2. 构建函数抽取](#2. 构建函数抽取)
    • [2.1. @Builder](#2.1. @Builder)
    • [2.2. @Builder传参传递](#2.2. @Builder传参传递)
  • [3. 构建函数插槽 @BuilderParam](#3. 构建函数插槽 @BuilderParam)
    • [3.1. 尾随闭包初始化组件(默认插槽)](#3.1. 尾随闭包初始化组件(默认插槽))
    • [3.2. 参数初始化组件(具名插槽)](#3.2. 参数初始化组件(具名插槽))

引言

在鸿蒙应用开发中,随着应用复杂度的提升,如何有效地组织和管理代码成为了一个重要的课题。

本文将探讨如何通过组件化和构建函数的使用来优化代码结构,提高代码的可读性和可维护性。

我们将从组件化的基础开始,逐步深入到构建函数的高级用法,包括如何使用 @Builder@BuilderParam 来进一步增强组件的灵活性和复用性。

无论你是刚接触鸿蒙应用开发的新手还是有一定经验的开发者,都能从中获得实用的技巧和最佳实践。让我们一起探索这些强大的工具吧!

1. 组件化抽取

1.1. 组件拆分及导入导出

刚开始写鸿蒙代码时,我们的代码都是在一个文件中编写,如下:

  • 重复代码较多
  • 不利于维护
ts 复制代码
@Entry
@Component
struct ComponentPage {
  build() {
      Column() {
        Text("header")
          .width("100%")
          .height(200)
          .backgroundColor(Color.Pink)
        Text("content")
          .width("100%")
          .height(200)
          .backgroundColor(Color.Red)
        Text("footer")
          .width("100%")
          .height(200)
          .backgroundColor(Color.Yellow)
      }
  }
}

当页面特别复杂时,这样写会导致代码量太大,不利于后续维护,那么可以采用下面这种方式:

创建 components/layout 文件夹:

导出每个组件:

  • Header.ets
ts 复制代码
@Component
export struct Header {
  build() {
    Text("header")
      .width("100%")
      .height(200)
      .backgroundColor(Color.Pink)
  }
}
  • Content.ets
ts 复制代码
@Component
export struct Content {
  build() {
    Text("content")
      .width("100%")
      .height(200)
      .backgroundColor(Color.Red)
  }
}
  • Footer.ets
ts 复制代码
@Component
export struct Footer {
  build() {
    Text("footer")
      .width("100%")
      .height(200)
      .backgroundColor(Color.Yellow)
  }
}

主页面导入并使用:

  • 将子组件导入父组件
  • 在负组件中直接使用子组件即可
ts 复制代码
import { Header } from "../components/layout/Header";
import { Content } from "../components/layout/Content";
import { Footer } from "../components/layout/Footer";

@Entry
@Component
struct ComponentPage {
  build() {
      Column() {
        Header()
        Content()
        Footer()
      }
  }
}

当然了,在同一个文件中抽取组件也是可行的,如下:

  • 在同一文件中通过 @Component 装饰器创建子组件
  • 在父组件中引用即可
ts 复制代码
@Entry
@Component
struct Index {
  build() {
    Column() {
      ListModel()
    }
    .width("100%")
    .height("100%")
  }
}
// 同一文件中抽取组件
@Component
struct ListModel {
  build() {
    Text(`123`)
      .fontSize(24)
  }
}

2. 构建函数抽取

2.1. @Builder

页面抽取为组件后,组件中有一些相似的内容,又可以抽取为构建函数:

  • 将部分UI抽取为公共构建函数
ts 复制代码
@Component
export struct Header {
  // 组件内构建函数:不需要 function 关键字声明
  // 通过 this.ListModel() 调用
  @Builder ListModel() {
    Text(title)
      .fontSize(30)
      .width("100%")
      .height(100)
      .backgroundColor(Color.Pink)
  }

  build() {
    Column() {
      this.ListModel()
    }
  }
}

// 全局构建函数:需要 function 关键字声明
// 直接 ListModel() 调用
// @Builder function ListModel() {
//   Text("你好")
//     .fontSize(30)
//     .width("100%")
//     .height(100)
//     .backgroundColor(Color.Pink)
// }

2.2. @Builder传参传递

1)按值传递

  • 标题通过参数传递
  • 只传递一个参数
ts 复制代码
@Component
export struct Header {
  // 组件内构建函数:不需要 function 关键字声明
  // 通过 this.ListModel() 调用
  @Builder ListModel(title: string) {
    Text(title)
      .fontSize(30)
      .width("100%")
      .height(100)
      .backgroundColor(Color.Pink)
  }

  build() {
    Column() {
      this.ListModel("你好")
    }
  }
}

// 全局构建函数:需要 function 关键字声明
// 直接 ListModel() 调用
// @Builder function ListModel(title: string) {
//   Text(title)
//     .fontSize(30)
//     .width("100%")
//     .height(100)
//     .backgroundColor(Color.Pink)
// }

2)按引用传递

  • 名称总数通过参数传递
  • 可传递多个参数
  • 点击按钮增加总数
ts 复制代码
interface IOptions {
  name: string;
  count: number;
}

@Component
export struct Header {
  @State count: number = 1;

  // 组件内构建函数:不需要 function 关键字声明
  // 通过 this.ListModel() 调用
  @Builder ListModel(options: IOptions) {
    Text(`${options.name}-------------------${options.count}`)
      .width("100%")
      .height(20)
      .backgroundColor(Color.Pink)
  }

  build() {
    Column() {
      this.ListModel({name: "Header", count: this.count})
      this.ListModel({name: "Header", count: this.count * 2})
      this.ListModel({name: "Header", count: this.count * 4})
      Button("增加count").onClick(() => {
        this.count++;
      })
    }
  }
}

// 全局构建函数:需要 function 关键字声明
// 直接 ListModel() 调用
// @Builder function ListModel(options: IOptions) {
//   Text(`${options.name}-------------------${options.count}`)
//     .width("100%")
//     .height(20)
//     .backgroundColor(Color.Pink)
// }

注意:

  • 在使用 @Builder 复用逻辑时,可以支持传递参数,从而实现更灵活的UI渲染。
  • 参数可以是状态数据,但建议使用对象的方式进行传递(直接传递,无法实现视图更新)。
  • 可以使用 Component 来抽象组件,而 @Builder 则可以实现轻量级的UI复用。
  • 按引用传递,参数定义类型时,不能使用字面量形式,需要使用 interface 或者 type 定义。

3. 构建函数插槽 @BuilderParam

@BuilderParam 是一个装饰器,用于声明任意 UI 描述的一个元素,类似于 slot 占位符。

当开发者创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作。

若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。

为解决此问题,ArkUI 引入了 @BuilderParam 装饰器,@BuilderParam 用来装饰指向 @Builder 方法的变量,开发者可在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。

3.1. 尾随闭包初始化组件(默认插槽)

  • 组件后加 {} 书写,称为尾随闭包
  • 组件多次使用时,如未传递插槽,需通过 @Builder 声明默认内容
ts 复制代码
// @BuilderParam
@Entry
@Component
struct Index {
  build() {
    Column() {
      ListModel() {
        // 传递默认插槽
        Text("默认插槽")
          .fontSize(24)
      }
      // 此处未使用插槽
      ListModel()
    }
    .width("100%")
    .height("100%")
  }
}

@Component
struct ListModel {
  // 使用父组件的尾随闭包{}(@Builder装饰的方法)初始化子组件@BuilderParam
  @BuilderParam ListModelFn: () => void = this.ListModelDefaultFn;
  // 如果默认插槽未传递,则默认一个内容
  @Builder ListModelDefaultFn () {
    Text("这是默认内容")
  }
  build() {
    Column() {
      Text("尾随闭包")
        .fontSize(24)
      // 接收默认插槽
      this.ListModelFn()
    }
  }
}

3.2. 参数初始化组件(具名插槽)

  • @BuilderParam 装饰的方法可以是有参数和无参数的两种形式,需与指向的 @Builder 方法类型匹配。
  • @BuilderParam 装饰的方法类型需要和 @Builder 方法类型一致。
  • @BuilderParam 装饰的方法必须要有默认值,要不会报错,默认值是一个函数,通过 @Builder 装饰
ts 复制代码
@Entry
@Component
struct Index {
  @Builder HeaderContent() {
    Text("上部分内容")
      .fontColor(Color.White)
      .height(40)
      .backgroundColor(Color.Blue)
      .width("100%")
      .textAlign(TextAlign.Center)
  }
  @Builder FooterContent() {
    Text("下部分内容")
      .fontColor(Color.White)
      .height(40)
      .backgroundColor(Color.Blue)
      .width("100%")
      .textAlign(TextAlign.Center)
  }
  build() {
    Column({space:10}) {
      ListModel({ title:"中间内容",
        HeaderCon: this.HeaderContent, // 可以传递多个插槽,只传递,不调用
        FooterCon: () => { this.FooterContent() } // 也可以才有箭头函数的形式传递
      })
    }
    .width('100%')
    .height('100%')
  }
}

@Component
struct ListModel {
  title:string = "";
  @BuilderParam HeaderCon:() => void = this.Default;
  @BuilderParam FooterCon:() => void = this.Default;
  // 必须要有默认值,要不会报错
  @Builder Default () {
    Text("")
  }

  build() {
    Column(){
      // 组件中调用
      this.HeaderCon()

      Text(this.title)
        .width("100%")
        .height(40)
        .textAlign(TextAlign.Center)
        .fontColor(Color.White)
        .backgroundColor(Color.Red)

      // 组件中调用
      this.FooterCon()
    }
    .width("100%")
  }
}
相关推荐
程序员小刘10 分钟前
【HarmonyOS 5】运动健康开发实践介绍以及详细案例
华为·harmonyos
御承扬17 分钟前
从零开始开发纯血鸿蒙应用之网络检测
网络·华为·harmonyos
Georgewu12 小时前
【 HarmonyOS 5 入门系列 】鸿蒙HarmonyOS示例项目讲解
harmonyos
libo_202514 小时前
HarmonyOS5 元宇宙3D原子化服务开发实践
harmonyos
半路下车14 小时前
【Harmony OS 5】DevEco Testing重塑教育质量
harmonyos·arkts
90后的晨仔14 小时前
解析鸿蒙 ArkTS 中的 Union 类型与 TypeAliases类型
前端·harmonyos
风浅月明14 小时前
[Harmony]颜色初始化
harmonyos·color
风浅月明14 小时前
[Harmony]网络状态监听
harmonyos·网络状态
半路下车15 小时前
【Harmony OS 5】DevEco Testing在教育领域的应用与实践
harmonyos·产品
simple丶15 小时前
【HarmonyOS Relational Database】鸿蒙关系型数据库
harmonyos·arkts·arkui