【最新鸿蒙应用开发】——鸿蒙中的“Slot插槽”?@BuilderParam

构建函数-@BuilderParam 传递 UI

1. 引言

@BuilderParam 该装饰器用于声明任意UI描述的一个元素,类似slot占位符。 简而言之:就是自定义组件允许外部传递 UI

@Entry
@Component
struct Index {
  build() {
    Column({ space: 15 }) {
      SonCom() {
        // 直接传递进来(尾随闭包)
        Button('传入的结构')
          .onClick(() => {
            AlertDialog.show({ message: '点了 Button' })
          })
      }
    }
  }
}

2. 单个@BuilderParam参数

首先来看看单个的情况:

使用尾随闭包的方式传入:

  • 组件内有且仅有一个使用 @BuilderParam 装饰的属性,即可使用尾随闭包
  • 内容直接在 {} 传入即可 注意:
  • 此场景下自定义组件不支持使用通用属性。
@Component
struct SonCom {
  // 由外部传入 UI
  @BuilderParam ContentBuilder: () => void = this.defaultBuilder
​
  // 设置默认 的 Builder,避免外部不传入
  @Builder
  defaultBuilder() {
    Text('默认的内容')
  }
​
  build() {
    Column() {
      this.ContentBuilder()
    }
    .width(300)
    .height(200)
    .border({ width: .5 })
  }
}
​
@Entry
@Component
struct Index {
  build() {
    Column({ space: 15 }) {
      SonCom() {
        // 直接传递进来
        Button('传入的结构')
          .onClick(() => {
            AlertDialog.show({ message: '点了 Button' })
          })
      }
    }
  }
}

3. 多个@BuilderParam 参数

子组件有多个BuilderParam,必须通过参数的方式来传入

核心步骤:

  1. 自定义组件-定义: 添加多个 @BuilderParam ,并定义默认值

  2. 自定义组件-使用 通过参数的形式传入多个 Builder,比如这里的 SonCom({ titleBuilder: this.fTitleBuilder, contentBuilder: this.fContentBuilder })

需求:

  • 调整 卡片自定义组件,支持传入 UI PanelComp(){ // 此处传入 }

思路:

  • 直接大括号(尾随闭包)传入只需要设置一个BuilderParam即可:

@Component
struct PanelComp {
  title: string = ''
  more: string = ''
  @BuilderParam contentBuilder: () => void = this.defaultContentBuilder
  clickHandler: () => void = () => {
    AlertDialog.show({ message: '默认提示' })
  }
​
  @Builder
  defaultContentBuilder() {
    Text('默认的内容~')
  }
​
  build() {
    Column() {
      Row() {
        Text(this.title)
          .layoutWeight(1)
          .fontWeight(600)
        Row() {
          Text(this.more)
            .fontSize(14)
            .fontColor('#666666')
            .onClick(() => {
              this.clickHandler()
            })
          Image('/common/day08-10/ic_public_arrow_right.svg')
            .width(16)
            .fillColor('#666666')
        }
      }
      .padding(10)
​
      Row() {
        this.contentBuilder()
      }
      .height(100)
    }
    .borderRadius(12)
    .backgroundColor('#fff')
  }
}
​
@Entry
@Component
struct Index {
  build() {
    Column({ space: 15 }) {
      PanelComp({
        title: '评价(2000+)', more: '好评率98%', clickHandler() {
          console.log('传入的逻辑')
        }
      }) {
        Text('传入的标题')
          .fontSize(20)
          .fontWeight(600)
          .fontColor(Color.White)
          .backgroundColor(Color.Blue)
          .padding(10)
      }
​
      Row({ space: 15 }) {
        PanelComp({ title: '推荐', more: '查看全部' })
          .layoutWeight(1)
​
        PanelComp({ title: '体验', more: '4 条测评' })
          .layoutWeight(1)
      }
​
    }
    .height('100%')
    .padding(15)
    .backgroundColor('#f5f5f5')
  }
}

4. 使用场景

这里简单举例两个关于我项目中适合使用的场景:


4.1. 任务列表页面

  • 自定义插槽

@Preview
@Component
struct HmToggleCard {
  title: string = "测试"
  @State
  toggleCard: boolean = true // 默认是展开的
  @BuilderParam
  CardContent: () => void
  build() {
    Column() {
      Row() {
        Text(this.title)
          .fontSize(16)
          .fontColor($r('app.color.text_primary'))
          .fontWeight(600)
        Image(this.toggleCard ? $r("app.media.ic_btn_cut") :
        $r("app.media.ic_btn_add"))
          .width(24)
          .height(24)
          .onClick(() => {
            animateTo({ duration: 300 }, () => {
              this.toggleCard = !this.toggleCard
            })
​
          })
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
      .height(50)
​
      // 放置传入的内容
      if(this.CardContent && this.toggleCard) {
        this.CardContent()
      }
    }
    .padding({
      left: 19.5,
      right: 19.5,
      bottom: 18.5
    })
    .margin({
      left: 15,
      right: 15,
      top: 15
    })
    .backgroundColor($r('app.color.white'))
    .borderRadius(10)
  }
}
​
export  { HmToggleCard }


  • 页面中进行复用的主要代码:

build() {
  Column() {
    HmNavBar({ title: '任务详情' })
    Scroll(this.scroll) {
      // Scroll里面只能有一个组件
      Column() {
        HmToggleCard({ title: '基本信息' }) {
          this.getBaseContent()
        }
​
        HmToggleCard({ title: '车辆信息' }) {
          this.getTransLineContent()
        }
​
        HmToggleCard({ title: '司机信息' }) {
          this.getDriverContent()
        }
​
        if (this.taskDetailData.exceptionList?.length > 0) {
          HmToggleCard({ title: '异常信息' }) {
            this.getExceptionContent()
          }
        }
​
        if (this.taskDetailData.status === TaskTypeEnum.Waiting ||
          this.taskDetailData.status === TaskTypeEnum.Delivered ||
          this.taskDetailData.status === TaskTypeEnum.Finish
        ) {
          HmToggleCard({ title: '提货信息' }) {
            this.getPickUpContent()
          }
        }
​
​
        if (this.taskDetailData.status === TaskTypeEnum.Line ||
          this.taskDetailData.status === TaskTypeEnum.Delivered
          || this.taskDetailData.status === TaskTypeEnum.Finish
        ) {
          HmToggleCard({ title: '交货信息' }) {
            this.getDeliverContent()
          }
        }
​
      }
      .padding({
        bottom: 130
      })
    }
​
    if (this.taskDetailData.status !== TaskTypeEnum.Finish) {
      // 只有在非完成情况下 才显示底部按钮
      this.getBottomBtn()
    }
  }.backgroundColor($r('app.color.background_page'))
  .height('100%')
}

4.2. 设置页面

  • 自定义插槽

@Component
export struct MkCell {
  @Prop label: string = ''
  @Prop value: string = ''
  @Prop icon: ResourceStr = $r('app.media.ic_public_right')
  @Prop hasBorder: boolean = true
​
  @Builder
  DefaultLabelBuilder() {
    Text(this.label)
      .fontSize(14)
      .fontColor($r('app.color.black'))
  }
​
  @Builder
  DefaultIconBuilder() {
    Image(this.icon)
      .width(20)
      .aspectRatio(1)
      .fillColor($r('app.color.gray'))
  }
​
  @BuilderParam customLabel: () => void = this.DefaultLabelBuilder
  @BuilderParam customIcon: () => void = this.DefaultIconBuilder
​
  build() {
    Row({ space: 8 }) {
      this.customLabel()
      Blank()
      if (this.value) {
        Text(this.value)
          .fontSize(14)
          .fontColor($r('app.color.gray'))
      }
      this.customIcon()
    }
    .width('100%')
    .constraintSize({ minHeight: 50 })
    .border({ width: { bottom: this.hasBorder ? 0.6 : 0 }, color: $r('app.color.under') })
  }
}
​
​
@Component
export struct MkCellGroup {
  @Builder
  DefaultBuilder() {
  }
​
  @BuilderParam default: () => void = this.DefaultBuilder
​
  build() {
    Column() {
      this.default()
    }
    .border({
      width: { top: 0.6, bottom: 0.6 },
      color: $r('app.color.under')
    })
    .padding({ left: 16, right: 16 })
    .backgroundColor($r('app.color.white'))
  }
}
  • 页面中进行复用的主要代码:

  build() {
    Column() {
      MkNavbar({ title: '设置' })
      Column({ space: 8 }) {
        MkCellGroup() {
          // 尾随闭包,MkCellGroup中只有一个 BuilderParam 即可使用尾随闭包
          // 多个 BuilderParam 需要用{}进行传递
          MkCell({
            hasBorder: false, customLabel: () => {
              this.ProfileBuilder()
            }
          })
​
        }
​
          MkCellGroup() {
            MkCell({ label: '收货地址管理' })
            MkCell({ label: '账号安全' })
            MkCell({ label: '消息设置' })
            MkCell({ label: '隐私设置' })
            MkCell({ label: '通用设置', hasBorder: false })
          }
​
          MkCellGroup() {
            MkCell({ label: '退出登录', hasBorder: false })
              .onClick(() => {
                auth.removeUser()
                router.back()
              })
          }
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor($r('app.color.under'))
  }

5.总结

当开发者创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作。若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。为解决此问题,ArkUI引入了@BuilderParam装饰器,@BuilderParam用来装饰指向@Builder方法的变量(@BuilderParam是用来承接@Builder函数的),开发者可在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。该装饰器用于声明任意UI描述的一个元素,类似slot占位符。

1. 使用尾随闭包的方式传入:(开发者可以将尾随闭包内的内容看做@Builder装饰的函数传给@BuilderParam)

●组件内有且仅有一个使用 @BuilderParam 装饰的属性,即可使用尾随闭包。

●在初始化自定义组件时,组件后紧跟一个大括号“{}”形成尾随闭包场景。

注意:

●此场景下自定义组件不支持使用通用属性。

2. 多个@BuilderParam(无法使用尾随闭包)

需注意this指向正确。

以下示例中,Parent组件在调用this.componentBuilder()时,this指向其所属组件,即“Parent”。@Builder componentBuilder()通过this.componentBuilder的形式传给子组件@BuilderParam customBuilderParam,this指向在Child的label,即“Child”。@Builder componentBuilder()通过():void=>{this.componentBuilder()}的形式传给子组件@BuilderParam customChangeThisBuilderParam,因为箭头函数的this指向的是宿主对象,所以label的值为“Parent”。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/714350.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IPv6 ND 协议功能概述

ND 协议功能概述 ND(Neighbor Discovery,邻居发现)协议是 IPv6 的一个关键协议,它综合了 IPv4 中的 ARP,ICMP 路由发现和 ICMP 重定向等协议,并对它们做了改进。 作为 IPv6 的基础性协议,ND 协…

ppt添加圆角矩形,并调整圆角弧度方法

一、背景 我们看的论文,许多好看的图都是用PPT做的,下面介绍用ppt添加圆角矩形,并调整圆角弧度方法。 二、ppt添加圆角矩形,并调整圆角弧度 添加矩形: 在顶部工具栏中,点击“插入”选项卡。 在“插图”…

冒泡排序知识点

排序的基本概念 排序是计算机内经常进行的一种操作,其目的是将一组“无序”的记录调整为“有序”的记录序列。 常用的排序例子 8 7 1 5 4 2 6 3 9 把上面的这个无序序列变为有序(升序或者降序)序列的过程。 1 2 3 4 5 6 7 8 9&#xff0…

Spring运维之boo项目表现层测试加载测试的专用配置属性以及在JUnit中启动web服务器发送虚拟请求

测试表现层的代码如何测试 加载测试的专用属性 首先写一个测试 假定我们进行测试的时候要加一些属性 要去修改一些属性 我们可以写一个只在本测试有效的测试 写在配置里 测试 打印输出 我们把配置文件里面的配置注释掉后 我们同样可以启动 package com.example.demo;impo…

代码随想录——组合总和Ⅱ(Leetcode 40)需要回顾

题目链接 回溯 本题的难点在于:集合(数组candidates)有重复元素,但还不能有重复的组合。 思想:元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同。所以要去重的是同一树…

购物车店铺列表查询流程

购物车店铺列表查询流程 购物车结算流程图

嵌入式门槛高不高,工资怎么样?

一般来说,嵌入式岗位的准入门槛其实并不是特别高。通常情况下,只要能够熟练掌握 C 语言编程以及单片机相关知识,就能够去制作一些较为简单的电子产品,由此可见其门槛相对而言是比较低的,相应的薪水可能也不会特别高。 …

I2C 总线通信技术基础

1.0 I2C 技术基础 使用总线的目的:采用串行总线技术可以使系统的硬件设计大大简化、系统的体积减小、可靠性提高,同时,系统的更改和扩充变的极为容易。 通信中常用的串行拓展总线 I2C(Inter-Integrated Circuit )总线…

C语言程序设计-6 循环控制

C语言程序设计-6 循环控制 循环结构是程序中一种很重要的结构。其特点是,在给定条件成立时,反复执行某程序 段,直到条件不成立为止。给定的条件称为循环条件,反复执行的程序段称为循环体。C语 言提供了多种循环语句&a…

计算机网络知识点全面总结回顾

物理层 OSI模型:数据链路层(流量控制),从传输层开始端到端;每一层的元素都称为实体,同一层的是对等实体;三个重要概念:服务(下层为上层提供调用)&#xff0c…

【Linux】进程间通信1——管道概念,匿名管道

1.进程间通信介绍 进程是计算机系统分配资源的最小单位(严格说来是线程)。每个进程都有自己的一部分独立的系统资源,彼此是隔离的。为了能使不同的进程互相访问资源并进行协调工作,才有了进程间通信。 进程间通信,顾名…

1055 集体照(测试点3, 4, 5)

solution 从后排开始输出,可以先把所有的学生进行排序(身高降序,名字升序),再按照每排的人数找到中间位置依次左右各一个进行排列测试点3, 4, 5:k是小于10的正整数,则每…

记录一次root过程

设备: Redmi k40s 第一步, 解锁BL(会重置手机系统!!!所有数据都会没有!!!) 由于更新了澎湃OS系统, 解锁BL很麻烦, 需要社区5级以上还要答题。 但是,这个手机…

人工智能历史与现状

1 人工智能历史与现状 1.1 人工智能的概念和起源 1.1.1 人工智能的概念 人工智能 (Artificial Intelligence ,AI)是一门研究如何使计算机 能够模拟人类智能行为的科学和技术,目标在于开发能够感知、理解、 学习、推理、决策和解决问题的智能机器。人工智能的概念主要包含 以…

理解DDD设计

DDD的理解 领域驱动设计(Domain-Driven Design,DDD)是一种软件开发方法论,强调将业务领域作为软件设计的核心,以便更好地满足业务需求。DDD认为,软件开发的核心是理解业务,而不是实现技术。在D…

容器镜像外网同步方案

目录 一、目的 二、安装nexus 1、购买香港云主机​编辑 2、安装nexus 3、启动nexus 服务 4、放行安全组 三、配置nexus 1、登录nexus管理页面 2、修改nexus密码 3、创建 Blob 存储空间(可选) 4、创建 镜像代理仓库 5、Realms配置 四、拉取镜像 1、配置docker 2、…

【Python】Python实现解压rar文件

Python实现解压rar文件 零、需求 最近在开发一个填分数的应用,需要用到selenium,那么自然需要用到浏览器,浏览器内置到应用中,但是上传到GitCode的时候被限制了,单个文件大小只能是10M以内。所以只能压缩&#xff0c…

免费个人站 独立站 wordpress 自建网站

制作免费网站 | 免费网站构建器 | WordPress.com https://bioinformatics7.wordpress.com WordPress.com

运算符分为哪几类?哪些运算符常用作判断?简述运算符的优先级

运算符包含6大类:算术运算符、赋值运算符、比较运算符、逻辑运算符、位运算符、三元(目)运算符。 逻辑运算符常用作布尔判断 typeof 运算符: typeof 运算符用于确定变量或表达式的数据类型,并返回一个表示类型的字符串。 typeof …

力扣 SQL题目

185.部门工资前三高的所有员工 公司的主管们感兴趣的是公司每个部门中谁赚的钱最多。一个部门的 高收入者 是指一个员工的工资在该部门的 不同 工资中 排名前三 。 编写解决方案,找出每个部门中 收入高的员工 。 以 任意顺序 返回结果表。 返回结果格式如下所示。 …