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

鸿蒙5:自定义构建函数

注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下

如果大家觉得博主文章写的好的话,可以点下关注,博主会一直更新鸿蒙next相关知识

专栏地址: https://blog.csdn.net/qq_56760790/category_12794123.html

文章所属类目(HarmonyOS语言-ArkTS)

目录

1. 自定义构建函数

1.1 构建函数-@Builder

1.2 构建函数-传参传递 (值传递和引用传递)

1.3 构建函数-传递参数练习-Tabs组件使用

1.4 构建函数-@BuilderParam 传递UI

1.5 @BuilderParam传值

1.6 尾随闭包


1. 自定义构建函数

1.1 构建函数-@Builder

如果你不想在直接抽象组件,ArkUI还提供了一种更轻量的UI元素复用机制 @Builder,可以将重复使用的UI元素抽象成一个方法,在 build 方法里调用。称之为自定义构建函数

只要使用Builder修饰符修饰的内容,都可以做成对应的UI描述

@Entry@ComponentV2struct BuilderCase {@Locallist: string[] = ["A", "B","C", "D", "E", "F"]@BuildergetItemBuilder (itemName: string) {Row() {Text(`${itemName}. 选项`)}.height(60).backgroundColor("#ffe0dede").borderRadius(8).width("100%").padding({left: 20,right: 20})}build() {Column({ space: 10 }) {ForEach(this.list, (item: string) => {this.getItemBuilder(item)})}.padding(20)}}

用法- 使用@Builder修饰符修饰

@Entry@ComponentV2struct BuilderCase02 {build() {Column() {Row() {Row() {Text("异常时间")Text("2023-12-12")}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding({left: 15,right: 15}).borderRadius(8).height(40).backgroundColor(Color.White)}.padding({left: 10,right: 10})}.width('100%').height('100%').backgroundColor('#ccc').padding({ top: 30 })}}

  • 全局定义- @Builder function name () {}
@Entry@ComponentV2struct BuilderCase02 {build() {Column() {Column({ space: 10 }) {getCellContent("异常时间", "2023-12-12")getCellContent("异常位置", "回龙观")getCellContent("异常类型", "漏油")}}.width('100%').height('100%').backgroundColor('#ccc').padding({ top: 30 })}}@Builderfunction getCellContent(leftTitle: string, rightValue: string) {Row() {Row() {Text(leftTitle)Text(rightValue)}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding({left: 15,right: 15}).borderRadius(8).height(40).backgroundColor(Color.White)}.padding({left: 10,right: 10})}

1.2 构建函数-传参传递 (值传递和引用传递)

调用@Builder装饰的函数默认按值传递。当传递的参数为状态变量时,状态变量的改变不会引起@Builder方法内的UI刷新。所以当使用状态变量的时候,推荐使用按引用传递。

按引用传递参数时,传递的参数可为状态变量,且状态变量的改变会引起@Builder方法内的UI刷新。

@Builderexport function getCellContent(leftTitle: string, rightValue: string) {Row() {Row() {Text(leftTitle)Text(rightValue)}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding({left: 15,right: 15}).borderRadius(8).height(40).backgroundColor(Color.White)}.padding({left: 10,right: 10})}interface ParamObj {leftTitle: stringrightValue: string
}@Builderexport function getCellContentObj(obj: ParamObj) {Row() {Row() {Text(obj.leftTitle)Text(obj.rightValue)}.width('100%').justifyContent(FlexAlign.SpaceBetween).padding({left: 15,right: 15}).borderRadius(8).height(40).backgroundColor(Color.White)}.padding({left: 10,right: 10})}@Entry@ComponentV2struct BuilderCase03 {@Local area: string = '望京'build() {Column({ space: 20 }) {getCellContent("异常时间", "2023-12-12")getCellContent("异常位置", this.area)getCellContent("异常类型", "漏油")Divider()getCellContentObj({leftTitle: '异常位置',rightValue: this.area})Button('修改数据').onClick(() => {this.area = '黑龙江'})}.width('100%').height('100%').backgroundColor('#ccc').padding({ top: 30 })}}
  • 使用 @Builder 复用逻辑的时候,支持传参可以更灵活的渲染UI
  • 参数可以使用状态数据,不过需要建议通过对象的方式传入 @Builder

注意问题:

当参数存在两个或者两个以上的时候,就算通过对象字面量的形式传递,值的改变也不会引起UI刷新。

1.3 构建函数-传递参数练习-Tabs组件使用

上图中,是tabs组件中的tabbar属性,支持自定义builder,意味着我们可以定制它的样式

  • 准备八个图标放到资源目录下

  • 新建一个页面, 声明一个interface并建立四个数据的状态

interface TabInterface {name: stringicon: ResourceStrselectIcon: ResourceStrtitle: string
}

  • 循环生成对应的TabContent
interface TabInterface {name: stringicon: ResourceStrselectIcon: ResourceStrtitle: string
}@Entry@ComponentV2struct TabBarDemo {@Local list: TabInterface[] = [{icon: $r("app.media.ic_public_message"),selectIcon: $r('app.media.ic_public_message_filled'),name: 'wechat',title: '微信',}, {icon: $r('app.media.ic_public_contacts_group'),selectIcon: $r('app.media.ic_public_contacts_group_filled'),name: 'connect',title: '联系人',}, {icon: $r('app.media.ic_gallery_discover'),selectIcon: $r('app.media.ic_gallery_discover_filled'),name: 'discover',title: '发现',}, {icon: $r('app.media.ic_public_contacts'),selectIcon: $r('app.media.ic_public_contacts_filled'),name: 'my',title: '我的',}]build() {Tabs() {ForEach(this.list, (item: TabInterface) => {TabContent() {Text(item.title)}.tabBar(item.title)})}.barPosition(BarPosition.End)}}

此时,如果我们想实现图中对应的效果,就需要使用自定义Builder来做,因为TabContent的tabBar属性支持CustomBuilder类型,CustomBuilder类型就是builder修饰的函数

  • 在当前组件中声明一个builder函数

 @BuilderCommonTabBar (item: TabInterface) {Column () {Image(item.icon).width(20).height(20)Text(item.title).fontSize(12).fontColor("#1AAD19").margin({top: 5})}}

interface TabInterface {name: stringicon: ResourceStrselectIcon: ResourceStrtitle: string
}@Entry@ComponentV2struct TabBarDemo {@Local list: TabInterface[] = [{icon: $r("app.media.ic_public_message"),selectIcon: $r('app.media.ic_public_message_filled'),name: 'wechat',title: '微信',}, {icon: $r('app.media.ic_public_contacts_group'),selectIcon: $r('app.media.ic_public_contacts_group_filled'),name: 'connect',title: '联系人',}, {icon: $r('app.media.ic_gallery_discover'),selectIcon: $r('app.media.ic_gallery_discover_filled'),name: 'discover',title: '发现',}, {icon: $r('app.media.ic_public_contacts'),selectIcon: $r('app.media.ic_public_contacts_filled'),name: 'my',title: '我的',}]@BuilderCommonTabBar (item: TabInterface) {Column () {Image(item.icon).width(20).height(20)Text(item.title).fontSize(12).fontColor("#1AAD19").margin({top: 5})}}build() {Tabs() {ForEach(this.list, (item: TabInterface) => {TabContent() {Text(item.title)}.tabBar(this.CommonTabBar(item))})}.barPosition(BarPosition.End)}}

  • 定义一个数据来绑定当前tabs的激活索引
@Local currentIndex: number = 0

  • 根据当前激活索引设置不同的颜色的图标
@Builder CommonTabBar (item: TabInterface) {Column() {Image(item.name === this.list[this.currentIndex].name ? item.selectIcon : item.icon).width(20).height(20)Text(item.title).fontSize(12).fontColor(item.name === this.list[this.currentIndex].name ? "#1AAD19" : "#2A2929").margin({top: 5})}
}

1.4 构建函数-@BuilderParam 传递UI

插槽-Vue-Slot React-RenderProps

  • 把UI结构体的函数(Builder修饰的函数)当成参数传入到组件中,让组件放入固定的位置去渲染
  • 子组件接收传入的函数的修饰符/装饰器叫做BuilderParam

  • BuilderParam的基本使用 - 如何实现定制化Header?

使用BuilderParam的步骤

  • 前提:需要出现父子组件的关系
  • 前提:BuilderParam应出现在子组件中
  • 1. 子组件声明 @BuilderParam getConent: () => void
  • 2. BuilderParam的参数可以不给初始值,如果给了初始值, 就是默认内容
  • 3. 父组件传入的时候,它需要用builder修饰的函数又或者是 一个箭头函数中包裹着
  • 4. 调用builder函数的逻辑

  • 封装子组件
@Entry@ComponentV2struct BuildParamCase {build() {Column() {//   Header容器ChildHeader()}.width('100%')}}@ComponentV2struct ChildHeader {build() {Row() {// 左Text('返回')// 中Text('首页').layoutWeight(1).textAlign(TextAlign.Center)// 右Text('确定')}.width('100%').backgroundColor(Color.Pink).padding(20)}}

  • 子组件中定义 @BuilderParam 接受结构参数
@Entry@ComponentV2struct BuildParamCase {@BuilderLeftBuilder() {Image($r('sys.media.ohos_ic_compnent_titlebar_back')).width(20)}@BuilderCenterBuilder() {Row(){Text('最新推荐')Text('🔥')}.layoutWeight(1).justifyContent(FlexAlign.Center)}@BuilderRightBuilder(){Image($r('sys.media.ohos_ic_public_scan')).width(20)}build() {Column() {// Header容器ChildHeader({leftContent: this.LeftBuilder,centerContent: this.CenterBuilder,rightContent: this.RightBuilder})}.width('100%')}}@ComponentV2struct ChildHeader {@BuilderParam leftContent: ()=>void@BuilderParam centerContent: ()=>void@BuilderParam rightContent: ()=>voidbuild() {Row() {// 左this.leftContent()// 中this.centerContent()// 右this.rightContent()}.width('100%').backgroundColor(Color.Pink).padding(20)}}

  • 子组件中定义默认值

@Entry
@ComponentV2
struct BuildParamCase {@BuilderLeftBuilder() {Image($r('sys.media.ohos_ic_compnent_titlebar_back')).width(20)}@BuilderCenterBuilder() {Row(){Text('最新推荐')Text('🔥')}.layoutWeight(1).justifyContent(FlexAlign.Center)}@BuilderRightBuilder(){Image($r('sys.media.ohos_ic_public_scan')).width(20)}build() {Column() {// Header容器ChildHeader({centerContent: this.CenterBuilder,rightContent: this.RightBuilder})}.width('100%')}
}@ComponentV2
struct ChildHeader {@Builder leftDefault () {Text('返回')}@BuilderParam leftContent: ()=>void = this.leftDefault@BuilderParam centerContent: ()=>void@BuilderParam rightContent: ()=>voidbuild() {Row() {// 左this.leftContent()// 中this.centerContent()// 右this.rightContent()}.width('100%').backgroundColor(Color.Pink).padding(20)}
}

1.5 @BuilderParam传值

场景:二次封装组件,可以用列表组件渲染数据 - 但是每一个选项的UI具体结构由调用者决定

  • 拷贝图片到assets

📎图片.zip

  • 封装一个列表的组件,可以渲染传入的数组,结构也是用户自己定义

@ComponentV2struct GoodList {@Param list: object[] = [] // 不知道传过来什么类型, 统一用object@BuilderdefaultRender() {Text('默认结构')}@BuilderParam renderItem: (item: object) => void = this.defaultRenderbuild() {List({ space: 10 }) {ForEach(this.list, (item: object) => {ListItem() {this.renderItem(item)}})}.padding(20)}}

  • 父组件调用
import GoodList from '../components/GoodList'interface GoodItem {goods_name: stringgoods_price: numbergoods_img: stringgoods_count: numberid: number
}@Entry
@ComponentV2
struct ListBuilder {@Local list: GoodItem[] = [{"id": 1,"goods_name": "班俏BANQIAO超火ins潮卫衣女士2020秋季新款韩版宽松慵懒风薄款外套带帽上衣","goods_img": "assets/1.webp","goods_price": 108,"goods_count": 1,},{"id": 2,"goods_name": "嘉叶希连帽卫衣女春秋薄款2020新款宽松bf韩版字母印花中长款外套ins潮","goods_img": "assets/2.webp","goods_price": 129,"goods_count": 1,},{"id": 3,"goods_name": "思蜜怡2020休闲运动套装女春秋季新款时尚大码宽松长袖卫衣两件套","goods_img": "assets/3.webp","goods_price": 198,"goods_count": 1,},{"id": 4,"goods_name": "思蜜怡卫衣女加绒加厚2020秋冬装新款韩版宽松上衣连帽中长款外套","goods_img": "assets/4.webp","goods_price": 99,"goods_count": 1,},{"id": 5,"goods_name": "幂凝早秋季卫衣女春秋装韩版宽松中长款假两件上衣薄款ins盐系外套潮","goods_img": "assets/5.webp","goods_price": 156,"goods_count": 1,},{"id": 6,"goods_name": "ME&CITY女装冬季新款针织抽绳休闲连帽卫衣女","goods_img": "assets/6.webp","goods_price": 142.8,"goods_count": 1,},{"id": 7,"goods_name": "幂凝假两件女士卫衣秋冬女装2020年新款韩版宽松春秋季薄款ins潮外套","goods_img": "assets/7.webp","goods_price": 219,"goods_count": 2,},{"id": 8,"goods_name": "依魅人2020休闲运动衣套装女秋季新款秋季韩版宽松卫衣 时尚两件套","goods_img": "assets/8.webp","goods_price": 178,"goods_count": 1,},{"id": 9,"goods_name": "芷臻(zhizhen)加厚卫衣2020春秋季女长袖韩版宽松短款加绒春秋装连帽开衫外套冬","goods_img": "assets/9.webp","goods_price": 128,"goods_count": 1,},{"id": 10,"goods_name": "Semir森马卫衣女冬装2019新款可爱甜美大撞色小清新连帽薄绒女士套头衫","goods_img": "assets/10.webp","goods_price": 153,"goods_count": 1,}]@BuilderrenderItem() {Row({ space: 10 }) {Image('assets/1.webp').borderRadius(8).width(120).height(200)Column() {Text('芷臻(zhizhen)加厚卫衣2020春秋季女长袖韩版宽松短款加绒春秋装连帽开衫外套冬').fontWeight(FontWeight.Bold)Text("¥ 178").fontColor(Color.Red).fontWeight(FontWeight.Bold)}.padding({top: 5,bottom: 5}).alignItems(HorizontalAlign.Start).justifyContent(FlexAlign.SpaceBetween).height(200).layoutWeight(1)}.width('100%')}build() {Column() {GoodList({list: this.list,renderItem: () => {this.renderItem()}})}.width('100%').height('100%')}
}

  • 父组件接受传值,渲染
import GoodList from '../components/GoodList'interface GoodItem {goods_name: stringgoods_price: numbergoods_img: stringgoods_count: numberid: number
}@Entry@ComponentV2struct ListBuilder {@Local list: GoodItem[] = [{"id": 1,"goods_name": "班俏BANQIAO超火ins潮卫衣女士2020秋季新款韩版宽松慵懒风薄款外套带帽上衣","goods_img": "assets/1.webp","goods_price": 108,"goods_count": 1,},{"id": 2,"goods_name": "嘉叶希连帽卫衣女春秋薄款2020新款宽松bf韩版字母印花中长款外套ins潮","goods_img": "assets/2.webp","goods_price": 129,"goods_count": 1,},{"id": 3,"goods_name": "思蜜怡2020休闲运动套装女春秋季新款时尚大码宽松长袖卫衣两件套","goods_img": "assets/3.webp","goods_price": 198,"goods_count": 1,},{"id": 4,"goods_name": "思蜜怡卫衣女加绒加厚2020秋冬装新款韩版宽松上衣连帽中长款外套","goods_img": "assets/4.webp","goods_price": 99,"goods_count": 1,},{"id": 5,"goods_name": "幂凝早秋季卫衣女春秋装韩版宽松中长款假两件上衣薄款ins盐系外套潮","goods_img": "assets/5.webp","goods_price": 156,"goods_count": 1,},{"id": 6,"goods_name": "ME&CITY女装冬季新款针织抽绳休闲连帽卫衣女","goods_img": "assets/6.webp","goods_price": 142.8,"goods_count": 1,},{"id": 7,"goods_name": "幂凝假两件女士卫衣秋冬女装2020年新款韩版宽松春秋季薄款ins潮外套","goods_img": "assets/7.webp","goods_price": 219,"goods_count": 2,},{"id": 8,"goods_name": "依魅人2020休闲运动衣套装女秋季新款秋季韩版宽松卫衣 时尚两件套","goods_img": "assets/8.webp","goods_price": 178,"goods_count": 1,},{"id": 9,"goods_name": "芷臻(zhizhen)加厚卫衣2020春秋季女长袖韩版宽松短款加绒春秋装连帽开衫外套冬","goods_img": "assets/9.webp","goods_price": 128,"goods_count": 1,},{"id": 10,"goods_name": "Semir森马卫衣女冬装2019新款可爱甜美大撞色小清新连帽薄绒女士套头衫","goods_img": "assets/10.webp","goods_price": 153,"goods_count": 1,}]@BuilderrenderItem (item: GoodItem) {Row({ space: 10 }) {Image(item.goods_img).borderRadius(8).width(120).height(200)Column() {Text(item.goods_name).fontWeight(FontWeight.Bold)Text("¥ " + item.goods_price).fontColor(Color.Red).fontWeight(FontWeight.Bold)}.padding({top: 5,bottom: 5}).alignItems(HorizontalAlign.Start).justifyContent(FlexAlign.SpaceBetween).height(200).layoutWeight(1)}.width('100%')}build() {Column() {GoodList({list: this.list,renderItem: (item: object) => {this.renderItem(item as GoodItem)}})}.width('100%').height('100%')}}

1.6 尾随闭包

Column () { } 中大括号就是尾随闭包的写法

当我们的组件只有一个BuilderParam的时候,此时可以使用尾随闭包的语法

也就是像我们原来使用Column或者Row组件时一样,直接在大括号中传入

我们用尾随闭包来封装这样的组件,理解一下BuildParam的使用

首先封装一个Panel组件

@ComponentV2struct PanelComp {@Param leftText:string = '左侧标题'@BuilderParamrightContent:()=>void = this.defaultContent@BuilderdefaultContent(){Row({space:16}){Checkbox().select(true).shape(CheckBoxShape.CIRCLE)Text('是')}}build() {Row(){Text(this.leftText)this.rightContent()}.width('100%').padding(20).backgroundColor('#ccc').borderRadius(8).justifyContent(FlexAlign.SpaceBetween)}}export { PanelComp }

  • 接下来父组件使用,并分别传递左侧文字和右侧的结构
import { PanelComp } from '../components/PanelComp'@Entry@ComponentV2struct PanelPage {@Local isOn: boolean = false// @Builder rightContent() {//   Toggle({ type: ToggleType.Switch })// }build() {Column() {PanelComp({leftText: '低电量模式',// rightContent: this.rightContent}) {Toggle({type: ToggleType.Switch,isOn: $$this.isOn})}Text(this.isOn.toString()).fontSize(20)PanelComp({leftText: '设置'}) {Text('查看详情 >')}}.padding(20).width('100%').height('100%').backgroundColor(Color.Pink)}}

只有一个BuilderParam且不需要传参的时候,可以使用尾随闭包

注意:尾随闭包用空大括号就代表传递空内容,会替代默认内容

http://www.lryc.cn/news/576752.html

相关文章:

  • 提示技术系列——生成知识提示
  • HTTP中常见的Content-Type
  • 【HuggingFace】模型选型策略指南(读懂config.json)
  • RAG工作原理
  • 什么是MPC(多方安全计算,Multi-Party Computation)
  • LeetCode Hot 100 最大子数组和
  • HarmonyOS NEXT仓颉开发语言实战案例:小而美的旅行App
  • NLP文本增强——随机删除
  • HarmonyOS NEXT仓颉开发语言实战案例:健身App
  • 野生动物检测数据集介绍-5,138张图片 野生动物保护监测 智能狩猎相机系统 生态研究与调查
  • rabbitmq springboot 有哪些配置参数
  • ONLYOFFICE 协作空间 企业版使用秘籍-8.使用虚拟数据房间,处理机密文档更安全
  • 生物实验室安全、化学品安全
  • MATLAB变音系统设计:声音特征变换(男声、女声、童声互转)
  • fvcom 网格文件grd制作
  • 日线周线MACD指标使用图文教程,通达信指标
  • 什么是零知识证明(Zero-Knowledge Proof, ZKP)
  • BF的数据结构题单-省选根号数据结构 - 题单 - 洛谷 计算机科学教育新生态
  • 基于开源AI智能名片链动2+1模式S2B2C商城小程序源码的用户价值对接机制研究
  • IDE/IoT/实践小熊派LiteOS工程配置、编译、烧录、调试(基于 bearpi-iot_std_liteos 源码)
  • 阿里云-接入SLS日志
  • 抗辐照芯片技术在商业卫星领域的应用与突破
  • C++ 第四阶段 STL 容器 - 第一讲:详解 std::vector
  • llama.cpp学习笔记:后端加载
  • M1芯片最终oracle成功版本拉取方法及配置
  • 【Linux庖丁解牛】— 文件系统!
  • JDK21 基于 Spring-AI 集成大模型实现聊天机器人
  • 【智能协同云图库】智能协同云图库第三弹:基于腾讯云 COS 对象存储—开发图片模块
  • Leetcode 3598. Longest Common Prefix Between Adjacent Strings After Removals
  • [database] Closure computation | e-r diagram | SQL