当前位置: 首页 > news >正文

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

🎉 博客主页:【剑九_六千里-CSDN博客】【剑九_六千里-掘金社区】
🎨 上一篇文章:【HarmonyOS第四章:样式操作及渲染页面】
🎠 系列专栏:【HarmonyOS系列】
💖 感谢大家点赞👍收藏⭐评论✍

在这里插入图片描述

在这里插入图片描述

文章目录

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

引言

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

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

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

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

1. 组件化抽取

1.1. 组件拆分及导入导出

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

在这里插入图片描述

  • 重复代码较多
  • 不利于维护
@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
@Component
export struct Header {build() {Text("header").width("100%").height(200).backgroundColor(Color.Pink)}
}
  • Content.ets
@Component
export struct Content {build() {Text("content").width("100%").height(200).backgroundColor(Color.Red)}
}
  • Footer.ets
@Component
export struct Footer {build() {Text("footer").width("100%").height(200).backgroundColor(Color.Yellow)}
}

主页面导入并使用:

在这里插入图片描述

  • 将子组件导入父组件
  • 在负组件中直接使用子组件即可
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 装饰器创建子组件
  • 在父组件中引用即可
@Entry
@Component
struct Index {build() {Column() {ListModel()}.width("100%").height("100%")}
}
// 同一文件中抽取组件
@Component
struct ListModel {build() {Text(`123`).fontSize(24)}
}

2. 构建函数抽取

2.1. @Builder

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

在这里插入图片描述

  • 将部分UI抽取为公共构建函数
@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)按值传递

在这里插入图片描述

  • 标题通过参数传递
  • 只传递一个参数
@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)按引用传递

在这里插入图片描述

  • 名称总数通过参数传递
  • 可传递多个参数
  • 点击按钮增加总数
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 声明默认内容
// @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 装饰

@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%")}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • springboot+Loki+Loki4j+Grafana搭建轻量级日志系统
  • web自动化6-pytest⑦一些基本情况
  • 基于深度学习的物理仿真
  • CUDA--内存访问越界或无效的索引操作解决办法
  • 如何给 VMware Workstation 虚拟机配置代理
  • docker load 后镜像名称为空的问题解决
  • php json_decode 带反斜杠字符串json解析
  • 【haproxy】haproxy七层代理
  • 全网最适合入门的面向对象编程教程:35 Python的内置数据类型-文档字符串和__doc__属性
  • vue3中 ref 和 reactive 的区别
  • 【Android】ServiceNotFoundException: No service published for: search
  • C++从入门到起飞之——string类的模拟实现 全方位剖析!
  • Webpack插件
  • 什么是报表?分析报表在零售行业中的应用,并推荐“免费高质量”的报表工具
  • 8.9 C++
  • 10个最佳ES6特性 ES7与ES8的特性
  • el-input获取焦点 input输入框为空时高亮 el-input值非法时
  • httpie使用详解
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • Java 多线程编程之:notify 和 wait 用法
  • js递归,无限分级树形折叠菜单
  • js对象的深浅拷贝
  • LeetCode算法系列_0891_子序列宽度之和
  • Mysql5.6主从复制
  • Object.assign方法不能实现深复制
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • Spring思维导图,让Spring不再难懂(mvc篇)
  • win10下安装mysql5.7
  • 翻译:Hystrix - How To Use
  • 分布式事物理论与实践
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 基于 Babel 的 npm 包最小化设置
  • 聊聊flink的BlobWriter
  • 模型微调
  • 前端面试题总结
  • 如何邀请好友注册您的网站(模拟百度网盘)
  • 一文看透浏览器架构
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • 第二十章:异步和文件I/O.(二十三)
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • ‌U盘闪一下就没了?‌如何有效恢复数据
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #[Composer学习笔记]Part1:安装composer并通过composer创建一个项目
  • #1014 : Trie树
  • #宝哥教你#查看jquery绑定的事件函数
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • (20050108)又读《平凡的世界》
  • (3)(3.5) 遥测无线电区域条例
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (笔试题)分解质因式
  • (二)fiber的基本认识
  • (回溯) LeetCode 78. 子集
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (三)mysql_MYSQL(三)