十一、动态构建UI元素 原创
装饰器@Builder
装饰器@BuilderParam
<font style="color:rgba(0, 0, 0, 0.9);">BuilderParam</font>
该装饰器用于声明任意UI描述的一个元素,类似slot占位符。
链接
简而言之:就是自定义组件允许外部传递 UI
// SonCom 的实现略
@Entry
@Component
struct Index {
build() {
Column({ space: 15 }) {
SonCom() {
// 直接传递进来(尾随闭包)
Button('传入的结构')
.onClick(() => {
AlertDialog.show({ message: '点了 Button' })
})
}
}
}
}
2.1单个@BuilderParam参数
:::info 使用尾随闭包的方式传入:
- 组件内有且仅有一个使用 @BuilderParam 装饰的属性,即可使用尾随闭包
- 内容直接在 {} 传入即可
注意:
- 此场景下自定义组件不支持使用通用属性。
:::
@Component
struct SonCom {
// 1.设置默认 的 Builder,避免外部不传入
@Builder
defaultBuilder() {
Text('默认的内容')
}
// 2.定义 BuilderParam 接受外部传入的 ui,并设置默认值
@BuilderParam ContentBuilder: () => void = this.defaultBuilder
build() {
Column() {
// 3. 使用 @BuilderParam 装饰的成员变量
this.ContentBuilder()
}
.width(300)
.height(200)
.border({ width: .5 })
}
}
// 使用自定义组件时,就可以使用如下方式传递 UI
// 不传递时会使用默认值
SonCom(){
// 传入的 UI
}
:::info
- 添加自定义组件:
- 定义默认的 Builder
- 添加BuilderParam,添加类型,并设置默认的 Builder
- 组件内部使用 BuilderParam
- 外部使用自定义组件,分别测试传递,不传递 UI 的情况
:::
@Component
struct SonCom {
// 由外部传入 UI
@BuilderParam ContentBuilder: () => void = this.defaultBuilder
// 设置默认 的 Builder,避免外部不传入
@Builder
defaultBuilder() {
Text('默认的内容')
}
//自定义组件的build,
build() {
Column() {
//自定义组件通过@BuilderParam接收到的参数, 放在这里了
this.ContentBuilder()
}
.width(300)
.height(200)
.border({ width: .5 })
}
}
@Entry
@Component
struct Index {
build() {
Column({ space: 15 }) {
//自定义组件的单个组件参数通过尾随闭包传入
SonCom() {
// 直接传递进来
Button('传入的结构')
.onClick(() => {
AlertDialog.show({ message: '点了 Button' })
})
}
}
}
}
import text from '@ohos.graphics.text';
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Column() {
//4.1调用自定义组件, 什么也不传
myCom()
//4.2调用自定义组件, 传一个text
myCom(){
Text('新传入的text')
}
//4.3调用自定义组件, 传一个text
myCom(){
Button('新传入的button')
}
}
}
}
@Component
struct myCom {
//1.先写默认的构造器, 防止外部不传入
@Builder
defultBuilder(){
Text('默认的组件')
}
//2.定义可以接受组件参数的Builderparam
@BuilderParam
newBuider:()=>void = this.defultBuilder
build() {
Column(){
//3.在自定义组件中使用Builderparam
this.newBuider()
}
}
}
2.2多个@BuilderParam参数
子组件有多个BuilderParam,必须通过参数的方式来传入
:::info 核心步骤:
- 自定义组件-定义:
- 添加多个 @BuilderParam ,并定义默认值
- 自定义组件-使用
- 通过参数的形式传入多个 Builder,比如
SonCom({ titleBuilder: this.fTitleBuilder, contentBuilder: this.fContentBuilder })
:::
@Component
struct SonCom {
// 由外部传入 UI
@BuilderParam titleBuilder: () => void = this.titleDefaultBuilder
@BuilderParam contentBuilder: () => void = this.contentDefaultBuilder
// 设置默认 的 Builder,避免外部不传入
@Builder
titleDefaultBuilder() {
Text('默认标题')
}
@Builder
contentDefaultBuilder() {
Text('默认内容')
}
build() {
Column() {
Row() {
this.titleBuilder()
}
.layoutWeight(1)
Divider()
Row() {
this.contentBuilder()
}
.layoutWeight(1)
}
.width(300)
.height(200)
.border({ width: .5 })
}
}
@Entry
@Component
struct Index {
@Builder
fTitleBuilder() {
Text('传入的标题')
.fontSize(20)
.fontWeight(600)
.fontColor(Color.White)
.backgroundColor(Color.Blue)
.padding(10)
}
@Builder
fContentBuilder() {
Text('传入的标题')
.fontSize(20)
.fontWeight(600)
.fontColor(Color.White)
.backgroundColor(Color.Blue)
.padding(10)
}
build() {
Column({ space: 15 }) {
//{@BuilderParam的参数名:自己组件内的@Builder构建函数名}
SonCom({ titleBuilder: this.fTitleBuilder, contentBuilder: this.fContentBuilder })
}
}
}
装饰器@Styles
装饰器@Extend
装饰器@CustomDialog
自定义组件@Component
自定义组件基础
在ArkUI中,UI显示的内容均为组件,
由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。
相比于之前学习的轻量级 UI 复用机制 @Builder,
自定义组件的功能更为强大,因为自定义组件可以通过<font style="color:rgba(0, 0, 0, 0.9);">@Prop @Link @BuilderParam</font>
实现父子组件进行传递组件和参数。
开发中如果要进行 UI 或业务逻辑进行复用,需要掌握自定义组件的能力。
// HelloComponent 的实现略,后续补充
//父组件
@Entry
@Component
struct CustomComponentDemo {
build() {
Column() {
// 自定义组件
HelloComponent()
HelloComponent()
}
}
}
//子组件
@Component
struct HelloComponent {
}
1.1基本使用
:::success 说明
自定义组件名、类名、函数名不能和系统组件名相同。
:::
// 定义
@Component
struct MyComponent {
// 状态变量
@State message:string =''
build(){
// .... 描述 UI
}
}
//----------使用-----------
// 1.不传递参数使用
// MyComponent()
// 2.传递参数使用:通过传递参数的方式 设置子组件中 messsage 的值
// MyComponent({message:'xxx'})
- struct:自定义组件基于struct实现,struct + 自定义组件名 + {...}的组合构成自定义组件,不能有继承关系。对于struct的实例化,可以省略new。
- @Component:@Component装饰器仅能装饰struct关键字声明的数据结构。
- build()函数:build()函数用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数。
- @Entry:@Entry装饰的自定义组件将作为UI页面的入口。在单个UI页面中,最多可以使用@Entry装饰一个自定义组件。
- @Preview:如果想要单独预览组件,可以使用@Preview 进行装饰
1.2成员函数/变量
自定义组件除了必须要实现build()函数外,还可以定义其他的成员函数,以及成员变量
:::info 注意:
- 不支持静态函数、静态成员变量
- 成员函数、变量均为私有
:::
@Component
struct MyComponent {
// 状态变量
@State message:string=''
// 成员变量-数据
info:string = ''
// 成员变量-函数
sayHello=()=>{}
// 成员函数
sayHi(){
}
build(){
// .... 描述 UI
}
}
:::info
- 添加自定义组件
- 定义成员变量(普通变量、状态变量)
- 定义成员函数
- 调用函数,修改成员变量(普通变量、状态变量)
- 使用自定义组件
- 无参数调用
- 传递参数调用
:::
// HelloComponent.ets
@Component
export struct HelloComponent {
// 成员变量
info: string = '感觉自己闷闷哒'
// 成员变量也可以是函数
sayHello=()=>{}
// 状态变量
@State message: string = 'Hello, World!';
// 成员函数
sayHi() {
console.log('你好呀')
}
build() {
// HelloComponent自定义组件组合系统组件Row和Text
Column() {
Text(this.message)
Text(this.info)
Button('修改数据')
.onClick(() => {
this.info = '(*  ̄3)(ε ̄ *)'
this.message = 'Hello,ArkTS'
this.sayHi()
this.sayHello()
})
}
}
}
// 页面的.ets
import { HelloComponent } from './components/HelloComponent'
@Entry
@Component
struct CustomComponentDemo {
build() {
Column() {
// 使用组件内部定义的初始值
HelloComponent()
// 使用传入的值,覆盖子组件的默认值
HelloComponent({ info: '你好', message: 'ArkTS' })
// 函数也可以传入
HelloComponent({ sayHello(){ console.log('传入的逻辑') } })
}
}
}
1.3通用样式
自定义组件可以通过点语法的形式设置通用样式,通用事件
子组件()
.width(100)
.height(100)
.backgroundColor(Color.Orange)
.onClick(() => {
console.log('外部添加的点击事件')
})
:::info
- 添加自定义组件,随意设置内容
- 使用自定义组件,通过点语法设置通用样式
:::
@Component
struct MyComponent2 {
build() {
Button(`Hello World`)
}
}
@Entry
@Component
struct MyComponent {
build() {
Row() {
MyComponent2()
.width(200)
.height(300)
.backgroundColor(Color.Red)
.onClick(() => {
console.log('外部添加的点击事件')
})
}
}
}
:::info 说明
ArkUI给自定义组件设置样式时,相当于给MyComponent2套了一个不可见的容器组件,而这些样式是设置在容器组件上的,而非直接设置给MyComponent2的Button组件。通过渲染结果我们可以很清楚的看到,背景颜色红色并没有直接生效在Button上,而是生效在Button所处的开发者不可见的容器组件上。
:::