鸿蒙应用开发-组件构建函数

自定义构建函数

1. 构建函数-@Builder

ArkUI还提供了一种更轻量的UI元素复用机制 @Builder,可以将重复使用的UI元素抽象成一个方法,在 build 方法里调用。

  • 组件内定义
  • 全局定义

1)组件内定义

@Builder MyBuilderFunction() {}

this.MyBuilderFunction()

2)全局定义

@Builder function MyGlobalBuilderFunction() {}

MyGlobalBuilderFunction()

📕📕📕 练习案例→商品详情-更多按钮

@Entry
@Component
struct Index {
  build() {
    Column() {
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          Column() {
            Row() {
              Text('评价(2000+)')
                .layoutWeight(1)
                .fontWeight(600)
              // TODO
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('推荐')
                .layoutWeight(1)
                .fontWeight(600)
              // TODO
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('体验')
                .layoutWeight(1)
                .fontWeight(600)
              // TODO
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

使用 @Builder 提取UI结构

@Entry
@Component
struct Index {

  @Builder
  MoreBuilder () {
    Row() {
      Text('查看更多')
        .fontSize(14)
        .fontColor('#666666')
      Image($r('app.media.ic_public_arrow_right'))
        .width(16)
        .fillColor('#666666')
    }
  }

  build() {
    Column() {
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          Column() {
            Row() {
              Text('评价(2000+)')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder()
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('推荐')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder()
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('体验')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder()
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

小结:

  • 遇到非遍历情况下,一个组件分散着相同的UI结构,可以使用 @Builder 更轻量
    其他:

  • GridRow GridCol 栅格布局

2. 构建函数-传参传递

1)按值传递(场景:构建不同的UI)

@Builder MyBuilderFunction( title: string ) {}

this.MyBuilderFunction('Title')

需求:不同板块查看更多文案不一样

  • 评价 好评率 98%

  • 推荐 查看全部

  • 体验 4 条测评

@Builder
  MoreBuilder (title: string) {
    Row() {
      Text(title)
        .fontSize(14)
        .fontColor('#666666')
      Image($r('app.media.ic_public_arrow_right'))
        .width(16)
        .fillColor('#666666')
    }
  }

this.MoreBuilder('好评率 98%')
this.MoreBuilder('查看全部')
this.MoreBuilder('4 条测评')

2)引用传递(场景:当传递的数据更新,需要更新UI)
需求:

  • 点击按钮后模拟加载好评率数据

@Entry
@Component
struct Index {
  @State
  rate: number = 0

  @Builder
  MoreBuilder(params: { title: string }) {
    Row() {
      Text(params.title)
        .fontSize(14)
        .fontColor('#666666')
      Image($r('app.media.ic_public_arrow_right'))
        .width(16)
        .fillColor('#666666')
    }
  }

  build() {
    Column() {
      Button('获取数据')
        .margin({ bottom: 15 })
        .onClick(() => {
          this.rate = 99
        })
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          Column() {
            Row() {
              Text('评价(2000+)')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder({ title: `好评率 ${this.rate} %` })
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('推荐')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder({ title: '查看全部' })
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }

        GridCol() {
          Column() {
            Row() {
              Text('体验')
                .layoutWeight(1)
                .fontWeight(600)
              this.MoreBuilder({ title: '4 条测评' })
            }
            .padding(10)

            Row()
              .height(100)
          }
          .borderRadius(12)
          .backgroundColor('#fff')
        }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

  • 使用** @Builder** 复用逻辑的时候,支持传参可以更灵活的渲染UI
  • 参数可以使用状态数据,不过建议通过对象的方式传入 @Builder
  1. 构建函数-@BuilderParam 传递UI
    @BuilderParam 该装饰器用于声明任意UI描述的一个元素,类似 slot 占位符

前置知识
组件属性初始化:

  • 定义组件声明属性 title: string
  • 使用组件初始化属性 Comp({ title: string })
  • 尾随闭包初始化组件

    • 组件内有且仅有一个使用 @BuilderParam 装饰的属性
  • 参数初始化组件

    • 组件内有多个使用 @BuilderParam 装饰器属性

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

需求:

  • 标题文字和更多文案通过属性传入

  • 内容结构需要传入

@Component
struct PanelComp {
  title: string
  more: string
  @BuilderParam
  panelContent: () => void = this.DefaultPanelContent

  // 备用 Builder
  @Builder
  DefaultPanelContent () {
    Text('默认内容')
  }

  build() {
    Column() {
      Row() {
        Text(this.title)
          .layoutWeight(1)
          .fontWeight(600)
        Row() {
          Text(this.more)
            .fontSize(14)
            .fontColor('#666666')
          Image($r('app.media.ic_public_arrow_right'))
            .width(16)
            .fillColor('#666666')
        }
      }
      .padding(10)

      Row() {
        this.panelContent()
      }
      .height(100)
    }
    .borderRadius(12)
    .backgroundColor('#fff')
  }
}

@Entry
@Component
struct Index {
  build() {
    Column() {
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          PanelComp({ title: '评价(2000+)', more: '好评率98%' })
        }

        GridCol() {
          PanelComp({ title: '推荐', more: '查看全部' }){
            Text('推荐内容')
          }
        }

        GridCol() {
          PanelComp({ title: '体验', more: '4 条测评' }){
            Text('体验内容')
          }
        }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

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

需求:需要传入内容结构和底部结构

@Component
struct PanelComp {
  title: string
  more: string
  @BuilderParam
  panelContent: () => void
  @BuilderParam
  panelFooter: () => void

  build() {
    Column() {
      Row() {
        Text(this.title)
          .layoutWeight(1)
          .fontWeight(600)
        Row() {
          Text(this.more)
            .fontSize(14)
            .fontColor('#666666')
          Image($r('app.media.ic_public_arrow_right'))
            .width(16)
            .fillColor('#666666')
        }
      }
      .padding(10)

      Row() {
        this.panelContent()
      }
      .height(100)
      Row() {
        this.panelFooter()
      }
      .height(50)
    }
    .borderRadius(12)
    .backgroundColor('#fff')
  }
}

@Entry
@Component
struct Index {
  @Builder
  ContentBuilderA() {
    Text('评价内容')
  }
  @Builder
  FooterBuilderA() {
    Text('评价底部')
  }

  build() {
    Column() {
      GridRow({ columns: 2, gutter: 15 }) {
        GridCol({ span: 2 }) {
          PanelComp({
            title: '评价(2000+)',
            more: '好评率98%',
            panelFooter: this.FooterBuilderA,
            panelContent: this.ContentBuilderA
          })
        }

        // GridCol() {
        //   PanelComp({ title: '推荐', more: '查看全部' }){
        //     Text('推荐内容')
        //   }
        // }
        //
        // GridCol() {
        //   PanelComp({ title: '体验', more: '4 条测评' }){
        //     Text('体验内容')
        //   }
        // }
      }
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

  • 当子组件使用一个 @BuilderParam 的时候,使用组件的时候在尾随 {} 插入UI结构
  • 当子组件使用多个 @BuilderParam 的时候,使用组件的时候 Comp({ xxx: this.builderFn }) 传入
  • 子组件本身可以提供一个默认的 @Builder 函数作为 @BuilderParam 备用函数,当做备用内容使用

4. 构建函数-系统组件自定义UI

在一些系统组件中,根据配置无法达到预期UI,可以使用 @Builder 构建函数自定义UI,前提该组件支持自定义。

在一些系统组件中,根据配置无法达到预期UI,可以使用 @Builder 构建函数自定义UI,前提该组件支持自定义。

需求:自定义 Tabs 组件的 TabBar UI结构

class ToolBarItem {
  defaultIcon: string | Resource
  activeIcon: string | Resource
  label: string
}

@Entry
@Component
struct Index {
  @State
  activeIndex: number = 0
  toolBars: ToolBarItem[] = [
    { defaultIcon: $r('app.media.home'), activeIcon: $r('app.media.home_select'), label: '首页' },
    { defaultIcon: $r('app.media.project'), activeIcon: $r('app.media.project_select'), label: '项目' },
    { defaultIcon: $r('app.media.interview'), activeIcon: $r('app.media.interview_select'), label: '面经' },
    { defaultIcon: $r('app.media.mine'), activeIcon: $r('app.media.mine_select'), label: '我的' }
  ]

  @Builder
  TabBarBuilder(item: ToolBarItem, index: number) {
    Column() {
      Image(this.activeIndex === index ? item.activeIcon : item.defaultIcon)
        .width(24)
      Text(item.label)
        .fontSize(12)
        .margin({ top: 4 })
        .lineHeight(12)
        .fontColor(this.activeIndex === index ? '#000' : '#aaa')
    }
  }

  build() {
    Tabs({
      index: this.activeIndex
    }) {
      ForEach(this.toolBars, (item: ToolBarItem, index: number) => {
        TabContent() {
          Text(index.toString())
        }
        .tabBar(this.TabBarBuilder(item, index))
      })
    }
    .barPosition(BarPosition.End)
    .onChange(index => this.activeIndex = index)
  }
}

最后资料分享

如果你还没有掌握鸿蒙,现在想要在最短的时间吃透它,大家可以参考一下这份鸿蒙学习路线图以及《鸿蒙(HarmonyOS)开发学习笔记》,内容包含ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

【扫描下方二维码即可免费领取!!】

在这里插入图片描述

快速入门

  • 开发准备
  • 构建第一个ArkTS应用(Stage模型)
  • 构建第一个ArkTS应用(FA模型)
  • 构建第一个JS应用(FA模型)
    在这里插入图片描述

开发基础知识

  • 应用程序包基础知识
  • 应用配置文件(Stage模型)
  • 应用配置文件概述(FA模型)
    在这里插入图片描述

资源分类与访问

  • 资源分类与访问
  • 创建资源目录和资源文件
  • 资源访问
    在这里插入图片描述

学习ArkTs语言

  • 初识ArkTS语言
  • 基本语法
  • 状态管理
  • 其他状态管理
  • 渲染控制
    在这里插入图片描述

基于ArkTS声明式开发范式

  • UI开发(ArkTS声明式开发范式)概述
  • 开发布局
  • 添加组件
  • 显示图片
  • 使用动画
  • 支持交互事件
  • 性能提升的推荐方法

在这里插入图片描述

兼容JS的类Web开发范式

  • 概述
  • 框架说明
  • 构建用户界面
  • 常见组件开发指导
  • 动效开发指导
  • 自定义组件
    在这里插入图片描述

Web组件

  • 概述
  • 设置基本属性和事件
  • 并发
  • 窗口管理
  • WebGL
  • 媒体
  • 安全
  • 网络与连接
  • 电话服务
  • 数据管理

  • 在这里插入图片描述

应用模型

  • 概述
  • Stage模型开发指导
  • FA模型开发指导
    在这里插入图片描述
有需要完整鸿蒙学习资料的朋友,扫描下方二维码即可免费领取!!!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值