前言
这一篇我是记录一些自定义组件、构建函数、公共样式与状态管理相关的知识。这部分知识我认为还是比较重要的,对于在开发中能提供很好的便利,有利项目的开发😏。下面让我们开始干货分享吧。
认识装饰器
1.自定义组件@Component
定义自定义组件使用@Component装饰器标识,当需要使用组件时,直接当函数调用一样。 如果需要传递参数,以对象形式传递,同时自定义组件内变量定义用private修饰。
@Component
struct MyComponent {
private title: string
build(){
Text(this.title)
}
}
@Entry
@Component
struct ItemPage {
build(){
MyComponent({title:'自定义组件'})
}
}
2.自定义构建函数@Builder
自定义构建函数分为全局自定义构建函数和局部自定义构建函数
主要使用@Build装饰器标识,语法:
- 全局自定义构建函:@Build function Builder(){ // UI描述 },调用时直接当函数一样
- 局部自定义构建函数:@Build Builder(){ //UI描述 },调用时需要用*this.*方式调用
// 全局自定义构建函数
@Builder function ItemCard(item: Item){
Row({space: 10}){
Image(item.image)
.width(100)
Column({space: 4}){
if(item.discount){
Text(item.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('原价:¥' + item.price)
.fontColor('#CCC')
.fontSize(14)
.decoration({type: TextDecorationType.LineThrough})
Text('折扣价:¥' + (item.price - item.discount))
.fontColor('#F36')
.fontSize(18)
Text('补贴:¥' + item.discount)
.fontColor('#F36')
.fontSize(18)
}else{
Text(item.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('¥' + item.price)
.fontColor('#F36')
.fontSize(18)
}
}
.height('100%')
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.backgroundColor('#FFF')
.borderRadius(20)
.height(120)
.padding(10)
}
// 局部自定义构建函数
@Builder ItemCard(item: Item){
Row({space: 10}){
Image(item.image)
.width(100)
Column({space: 4}){
if(item.discount){
Text(item.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('原价:¥' + item.price)
.fontColor('#CCC')
.fontSize(14)
.decoration({type: TextDecorationType.LineThrough})
Text('折扣价:¥' + (item.price - item.discount))
.priceText()
Text('补贴:¥' + item.discount)
.priceText()
}else{
Text(item.name)
.fontSize(20)
.fontWeight(FontWeight.Bold)
Text('¥' + item.price)
.priceText()
}
}
.height('100%')
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.backgroundColor('#FFF')
.borderRadius(20)
.height(120)
.padding(10)
}
2.1 传递参数
值传递:直接传递普通数据,不会引起UI跟新
引用传递:传递以对象形式传递,会引起UI更新
// 值传递
@Builder sendInfo($$){
Text($$)
// .onClick(() => {
// $$.mes = '999'
// })
}
this.sendInfo(this.sendInfoMes)
Button('123').onClick((event: ClickEvent) => {
this.sendInfoMes = '333'
})
// 引用传递
@Builder sendInfo($$:{mes:string}){
Text($$.mes)
// .onClick(() => {
// $$.mes = '999'
// })
}
this.sendInfo({mes:this.sendInfoMes})
Button('123').onClick((event: ClickEvent) => {
this.sendInfoMes = '333'
})
2.2 @BuilderParams 装饰,引用@Builder函数(类似于vue的插槽slot)
2.2.1 尾随闭包 @BuilderParams(默认插槽),只有一个@BuilderParams
一个组件只有一个@BuilderParams,就能使用尾随闭包
// 父组件
Column() {
child(){
Text('send message')
Button('点击事件')
}
}
// 子组件
@BuilderParam sendInfo:() => void = () => {}
build() {
Column(){
this.sendInfo()
Divider()
.strokeWidth(5)
}
}
// 父组件
@Builder parentInfo(){
Text('父亲组件')
}
Column() {
child({sendInfo: this.parentInfo})
}
.width('40%')
// 子组件
@BuilderParam sendInfo:() => void = () => {}
build() {
Column(){
this.sendInfo()
Divider()
.strokeWidth(5)
}
}
2.2.2 参数传递@Builder(具名插槽),多个@BuilderParams
一个组件有多个@BuilderParams,就不能使用尾随闭包,要参数指定传递
@Builder function IndexInfo() {
Button('公共自定义函数')
}
// 父组件
Column() {
child({sendInfo: this.parentInfo, sendInfo2:IndexInfo})
}
// 子组件
@BuilderParam sendInfo:() => void = () => {}
@BuilderParam sendInfo2:() => void = () => {}
build() {
Column(){
this.sendInfo()
this.sendInfo2()
Divider()
.strokeWidth(5)
}
}
3.公共样式@Styles,封装组件通用属性
公共样式分为全局公共样式和局部公共样式
主要使用@Styles装饰器标识,语法:
- 全局公共样式:@Styles function fillStyle(){ // 样式 },调用时直接当函数一样,前面加.
- 局部公共样式:@Styles normalStyle(){ // 样式 },调用时当函数用,前面加.
// 全局公共样式函数
@Styles function fillScreen(){
.width('100%')
.height('100%')
.backgroundColor('#EFEFEF')
.padding(20)
}
// 局部公共样式函数
@Styles fillScreen(){
.width('100%')
.height('100%')
.backgroundColor('#EFEFEF')
.padding(20)
}
4. 公共样式@Extend,封装组件特有属性,只能定义在全局
语法:@Extend(继承的组件) fucntion 函数名(){}
// 继承模式,只能写在全局
@Extend(Text) function priceText(){
.fontColor('#F36')
.fontSize(18)
}
5. 多态样式属性.stateStyles
使用多态样式属性stateStyles可以对不同触发条件下设置不同样式。
语法:.stateStyles({normal,pressed,focused,clicked})
.stateStyles({
normal: this.changeColor,
// pressed: {
// .backgroundColor(Color.Gray)
// },
focused: {
.backgroundColor(Color.Orange)
},
clicked: itemStyles
})
6.@State装饰器
定义变量时,使用@State标识,此变量就可以实现数据驱动视图更新
注意:
- @State装饰器标记的变量必须初始化,不能为空值
- @State支持Object,class,string,number,boolean,enum类型以及这些类型的数组
- 嵌套类型以及数组中的对象属性无法触发视图更新,即不能深层次更新
7.@Prop装饰器和@Link装饰器
当需要父子组件之间数据同步时,可以使用@Prop和@Link去定义数据以实现数据传递。 @Prop的使用:
注意:父组件@State,子组件@Prop,传数据this.
// 父组件
@State totalTask: number = 0
@State finishTask: number = 0
@State tasks: Task[] = []
@Styles normalStyle(){
.width('100%')
.height('100%')
}
build(){
Column({space:10}){
TaskStatistics({finishTask: this.finishTask,totalTask:this.totalTask})
TaskList({finishTask: $finishTask,totalTask:$totalTask})
}
// 子组件
@Prop totalTask: number
@Prop finishTask: number
build(){
Row(){
Text('任务进度:')
.fontSize(30)
.fontWeight(FontWeight.Bold)
Stack(){
Progress({
value:this.finishTask,
total: this.totalTask,
type: ProgressType.Ring
})
@Link的使用
注意:父组件@State,子组件@Link,不初始化数据,传数据$
// 父组件
@State totalTask: number = 0
@State finishTask: number = 0
@State tasks: Task[] = []
@Styles normalStyle(){
.width('100%')
.height('100%')
}
build(){
Column({space:10}){
TaskStatistics({finishTask: this.finishTask,totalTask:this.totalTask})
TaskList({finishTask: $finishTask,totalTask:$totalTask})
}
// 子组件
@Link totalTask: number
@Link finishTask: number
@State tasks: Task[] = []
handleChange(){
this.totalTask = this.tasks.length
this.finishTask = this.tasks.filter(item => item.finished).length
}
8.@Provide装饰器和@Consume装饰器
@Provide装饰器和@Consume装饰器可以跨组件提供类似于@State和@Link的双向同步
使用时,父组件@Provide,子组件@Consume,不初始化数据,同时不用传递东西,父子组件定义名字要一样
// 父组件
@Provide totalTask: number = 0
@Provide finishTask: number = 0
@Provide tasks: Task[] = []
@Styles normalStyle(){
.width('100%')
.height('100%')
}
build(){
Column({space:10}){
TaskStatistics({finishTask: this.finishTask,totalTask:this.totalTask})
TaskList()
}
// 子组件
@Consume totalTask: number
@Consume finishTask: number
@State tasks: Task[] = []
handleChange(){
this.totalTask = this.tasks.length
this.finishTask = this.tasks.filter(item => item.finished).length
}
9. @Observed装饰器和@ObjectLink装饰器
对于涉及嵌套对象和数组元素为对象的场景中进行双向数据同步,可以使用@Observed装饰器和@ObjectLink装饰器。
10. @Watch装饰器
@Watch应用于对状态变量的监听。如果开发者需要关注某个状态变量的值是否改变,可以使用@Watch为状态变量设置回调函数。
@Watch用于监听状态变量的变化,当状态变量变化时,@Watch的回调方法将被调用。@Watch在ArkUI框架内部判断数值有无更新使用的是严格相等(===),遵循严格相等规范。当在严格相等为false的情况下,就会触发@Watch的回调。
语法:@Watch((changedPropertyName? : string) => void)
该函数是自定义组件的成员函数,changedPropertyName是被watch的属性名。在多个状态变量绑定同一个@Watch的回调方法的时候,可以通过changedPropertyName进行不同的逻辑处理将属性名作为字符串输入参数,不返回任何内容。
@State @Watch('changeCount') count: number = 1
@State @Watch('changePow') pow: number = 2
@State res: number = 1
changeCount(){
this.res = Math.pow(this.count, this.pow)
}
changePow(){
this.res = Math.pow(this.count, this.pow)
}
注意:
- @Watch一定要用于被装饰器装饰的变量(@State,@Prop,@Link等)
- @Watch的函数里面不对进行监控的变量进行修改,会进入死循环
学习我是通过传智博学谷的鸿蒙教程,然后自己总结并作笔记,文章可能更新的有点慢,和我的学习进度挂钩。😏