HarmonyOS之常用装饰器

109 阅读6分钟

前言

这一篇我是记录一些自定义组件、构建函数、公共样式与状态管理相关的知识。这部分知识我认为还是比较重要的,对于在开发中能提供很好的便利,有利项目的开发😏。下面让我们开始干货分享吧

认识装饰器

1.自定义组件@Component

定义自定义组件使用@Component装饰器标识,当需要使用组件时,直接当函数调用一样。 如果需要传递参数,以对象形式传递,同时自定义组件内变量定义用private修饰

@Component
struct MyComponent {
private title: string
build(){
Text(this.title)
}
}
​
@Entry
@Component
struct ItemPage {
build(){
MyComponent({title:'自定义组件'})
}
}

2.自定义构建函数@Builder

自定义构建函数分为全局自定义构建函数局部自定义构建函数

主要使用@Build装饰器标识,语法:

  1. 全局自定义构建函:@Build function Builder(){ // UI描述 },调用时直接当函数一样
  2. 局部自定义构建函数:@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装饰器标识,语法:

  1. 全局公共样式:@Styles function fillStyle(){ // 样式 },调用时直接当函数一样,前面加.
  2. 局部公共样式:@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标识,此变量就可以实现数据驱动视图更新

注意

  1. @State装饰器标记的变量必须初始化,不能为空值
  2. @State支持Object,class,string,number,boolean,enum类型以及这些类型的数组
  3. 嵌套类型以及数组中的对象属性无法触发视图更新,即不能深层次更新

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 = 1changeCount(){
    this.res = Math.pow(this.count, this.pow)
  }
  changePow(){
    this.res = Math.pow(this.count, this.pow)
  }

注意:

  1. @Watch一定要用于被装饰器装饰的变量(@State,@Prop,@Link等)
  2. @Watch的函数里面不对进行监控的变量进行修改,会进入死循环

学习我是通过传智博学谷鸿蒙教程,然后自己总结并作笔记,文章可能更新的有点慢,和我的学习进度挂钩。😏