大家好,我是鸿蒙开天组,今天咱们来学习自定义组件。
一、自定义组件定义
在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。在进行 UI 界面开发时,通常不是简单的将系统组件进行组合使用,而是需要考虑代码可复用性、业务逻辑与UI分离,后续版本演进等因素。因此,将UI和部分业务逻辑封装成自定义组件是不可或缺的能力。
相比于之前学习的轻量级 UI 复用机制 @Builder,自定义组件的功能更为强大,日常开发中如果要对 【UI 或业务逻辑】进行复用,需要【掌握】自定义组件的能力。
二、自定义组件特点
自定义组件具有以下特点:
-
可组合:允许开发者组合使用系统组件、及其属性和方法。
-
可重用:自定义组件可以被其他组件重用,并作为不同的实例在不同的父组件或容器中使用。
-
数据驱动UI更新:通过状态变量的改变,来驱动UI的刷新。
三、自定义组件基本用法
1.1自定义组件创建
首先自定义组件需要创建出来,创建的自定义组件基本语法如下:
// 创建
@Component
struct MyComponent {
// 状态变量
@State message:string =''
build(){
// .... 描述 UI
}
}
观察以上结构,主要分成三个部分,可以理解成这是自定义组件创建的固定写法:
- @Component:@Component装饰器仅能装饰struct关键字声明的数据结构。
- struct:自定义组件基于struct实现,struct + 自定义组件名 + {...}的组合构成自定义组件,不能有继承关系。对于struct的实例化,可以省略new。
- build()函数:build()函数用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数。
要注意的是,struct后面的自定义组件名,这个名称就是自定义组件的标记,不能和系统组件名相同,比如不能命名成Text、Image等
有些细心的同学可能已经注意到,这个结构和咱们平时打开的默认页面结构很像,但是默认页面上,还多出了一个@Entry:
- @Entry:@Entry装饰的自定义组件将作为UI页面的入口。在单个UI页面中,最多可以使用@Entry装饰一个自定义组件。
在我们的单个组件中,没有使用@Entry去装饰的时候,想要单独预览它的效果,也可以考虑使用@Preview装饰,再点击预览器即可预览效果。
1.2自定义组件使用
接下来是自定义组件的使用,使用当然是丢进有@Entry装饰的UI页面里了,我们用一个简单的例子来看看自定义组件的基本用法,上代码演示:
@Component
struct HelloComponent {
@State message: string = 'mate70还没发布';
build() {
// HelloComponent自定义组件组合系统组件Row和Text
Row() {
Text(this.message)
.onClick(() => {
// 状态变量message的改变驱动UI刷新,UI从'mate70还没发布'或'mate70发布了'刷新为'mate70发布啦啊啊啊!'
this.message = 'mate70发布啦啊啊啊!';
})
.width('100%')
.height(60)
.fontSize(20)
.backgroundColor('#E6E6E6')
.textAlign(TextAlign.Center)
}
}
}
/*-----------------------两个组件之间的分割线-------------------------*/
class HelloComponentParam {
message: string = ""
}
@Entry
@Component
struct ParentComponent {
param: HelloComponentParam = {
message: 'mate70发布了'
}
build() {
Column() {
Text('mate70发布了吗?')
.fontSize(20)
.width('100%')
.height(60)
.backgroundColor('#E6E6E6')
.textAlign(TextAlign.Center)
HelloComponent();
Divider()
HelloComponent(this.param);
}
}
}
点击前后的效果分别如下:
1.3自定义组件传值
自定义组件除了必须要实现build()函数外,其他【属性】和【方法】的写法跟之前一样,也可以通过点语法设置通用样式,由于都和之前一样,这里就不再说明。
而从上面的例子,我们还可以看出,使用自定义组件时,小括号中没有传值,就会使用自定义组件HelloComponent中定义的message默认值,即“mate70还没发布”;如果在小括号中传同名的值即message时,默认值就会被覆盖,显示为“mate70发布了”。
以上例子上,我们可以把ParentComponent称为父组件,而在它内部调用的HelloComponent称之为子组件,往后这种父组件和子组件之间的参数传递会非常常见。
1.4传递回调参数
使用自定义组件时还有一种传递回调函数的写法,这种写法非常重要。咱们来看看它的适用场景:
- 需要父组件传递【逻辑代码】给子组件
- 在 1 的基础上,子组件需要【传递数据】给父组件
基础代码结构如下:
@Component
struct 子组件 {
// 1.定义箭头函数
func1 = () => {}
func2 = (参数: 类型) => {}
build() {
// 略 2.根据情境调用 func1,func2并传递参数
}
}
@Entry
@Component
struct 父组件 {
build() {
子组件({
// 3. 父组件传递回调函数给子组件
func1: () => {
// 具体的逻辑
},
func2: (参数: 类型) => {
// 具体的逻辑
}
})
}
}
比如通过定义子组件的箭头函数,实现点击+1到+4的累加效果,这是不传递参数的写法:
@Component
struct addCom {
// 1. 定义点击+1-+4的箭头函数
addOne = () => {
}
addTwo = () => {
}
addThree = () => {
}
addFour = () => {
}
build() {
Column() {
Text('累加器')
.fontSize(20)
Row() {
// 2. 调用+1-+4对应的回调函数
Button('点击+1')
.onClick(() => {
this.addOne()
})
Button('点击+2')
.onClick(() => {
this.addTwo()
})
Button('点击+3')
.onClick(() => {
this.addThree()
})
Button('点击+4')
.onClick(() => {
this.addFour()
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
}
.border({ width: 1 })
.padding(5)
}
}
@Entry
@Component
struct Page04_callback {
@State num: number = 0
build() {
Column() {
Text('回调函数')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Text('num:' + this.num)
.fontSize(30)
addCom({
// 3. 传递回调函数
addOne: () => {
this.num++
},
addTwo: () => {
this.num += 2
},
addThree: () => {
this.num += 3
},
addFour: () => {
this.num += 4
}
})
}
.height('100%')
}
}
但如果使用参数传递,可以简化代码书写,改写结果如下,功能是相同的:
@Component
struct addCom {
// 点击+1-+4的箭头函数
addCount = (count: number) => {
}
build() {
Column() {
Text('累加器-传递参数')
.fontSize(20)
Row() {
Button('点击+1')
.onClick(() => {
this.addCount(1)
})
Button('点击+2')
.onClick(() => {
this.addCount(2)
})
Button('点击+3')
.onClick(() => {
this.addCount(3)
})
Button('点击+4')
.onClick(() => {
this.addCount(4)
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
}
.border({ width: 1 })
.padding(5)
}
}
@Entry
@Component
struct Page04_callback {
@State num: number = 0
build() {
Column() {
Text('回调函数')
.fontSize(50)
.fontWeight(FontWeight.Bold)
Text('num:' + this.num)
.fontSize(30)
addCom({
addCount: (count: number) => {
this.num += count
}
})
}
.height('100%')
}
}
好了,关于自定义组件的分享就到这里,感谢阅读,你的点赞和收藏都是莫大的支持,谢谢!