HarmonyOS鸿蒙Next中AskTs中的装饰器

HarmonyOS鸿蒙Next中AskTs中的装饰器 @Builder装饰器

作用:轻量级的UI元素复用机制,可以将重复使用的UI元素抽象成一个方法,在build方法中使用。自定义构建函数又有2种传递规则,分别是按值传递和按引用传递。

组件内公共样式的两种方案

1、私有自定义构建函数

[@Entry](/user/Entry)
[@Component](/user/Component)
struct BuilderDemo {
  [@Builder](/user/Builder)
  showTextBuilder(param: string) {
    Text('Hello World')
      .fontSize(30)
      .fontWeight(FontWeight.Bold)
  }
  [@Builder](/user/Builder)
  showTextValueBuilder(param: string) {
    Text(param)
      .fontSize(30)
      .fontWeight(FontWeight.Bold)
  }
  build() {
    Column() {
      // 无参数
      this.showTextBuilder()
      // 有参数
      this.showTextValueBuilder('Hello [@Builder](/user/Builder)')
    }
  }
}

使用方法:this.showTextBuilder()

2、全局自定义构建函数

[@Builder](/user/Builder)
function showTextBuilder() {
  Text('Hello World')
    .fontSize(30)
    .fontWeight(FontWeight.Bold)
}
[@Entry](/user/Entry)
[@Component](/user/Component)
struct BuilderDemo {
  build() {
    Column() {
      showTextBuilder()
    }
  }
}

使用方法:showTextBuilder()

注意:

1、如果不设计组件状态变化,建议使用全局的自定义构建方法。 2、全局自定义构建函数允许在build方法和其他自定义构建函数种调用

参数传递规则

1、 按值传递参数:调用@Builder装饰的函数默认按值传递。当传递的参数为状态变量时,不会引起方法的内部刷新。

[@Builder](/user/Builder) function overBuilder(paramA1: string) {
  Row() {
    Text(`UseStateVarByValue: ${paramA1} `)
  }
}
[@Entry](/user/Entry)
[@Component](/user/Component)
struct Parent {
  [@State](/user/State) label: string = 'Hello';
  build() {
    Column() {
      overBuilder(this.label)
    }
  }
}

2、按引用传递参数:传递的参数可以为状态变量,且状态变量的改变会引起方法的内部刷新。

class Tmp {
  paramA1: string = '';
}

[@Builder](/user/Builder) function overBuilder(params: Tmp) {
  Row() {
    Text(`UseStateVarByReference: ${params.paramA1} `)
  }
}
[@Entry](/user/Entry)
[@Component](/user/Component)
struct Parent {
  [@State](/user/State) label: string = 'Hello';
  build() {
    Column() {
      // 在父组件中调用overBuilder组件时,
      // 把this.label通过引用传递的方式传给overBuilder组件。
      overBuilder({ paramA1: this.label })
      Button('Click me').onClick(() => {
        // 单击Click me后,UI文本从Hello更改为ArkUI。
        this.label = 'ArkUI';
      })
    }
  }
}

注意:

1、函数内部,不允许修改参数值,开发者可以在调用函数的自定义组件里改变其参数 2、按引用传递的访问才会触发动态UI渲染,并且参数只能是一个。(只有传入一个参数,且参数需要直接传入对象字面量才会按引用传递该参数,其余传递方式均为按值传递) 3、如果传入的参数是两个或者以上,不会触发动态渲染。如何实现?多个参数触发动态渲染。参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-builder#builder存在两个或者以上参数 4、传入的参数中含有值传递和引用传递两种方式,不会触发动态渲染。

@Styles装饰器

作用:将页面中重复的一些样式代码提取出来公用且只负责当前页面的样式复用

组件内公共样式有两种方案:

1、组件内的定义

[@Entry](/user/Entry)
[@Component](/user/Component)
struct Text{
    [@Styles](/user/Styles) titleText(){
        .width(100)
        .height(100)
        .backgroundColor(Color.Red)
        .borderRadius(10)
    }
    build(){
        column().titleText()
    }
}

注意:不是所有的样式都可以提取到@Style装饰器中。一般默认是容器的布局属性可以提取出来,但是字体或者文本样式,不支持提取。

2、组件外定义

[@Styles](/user/Styles) function titleText(){
    .width(100)
    .height(100)
    .backgroundColor(Color.Red)
    .borderRadius(10)
}

[@Entry](/user/Entry)
[@Component](/user/Component)
struct Text{
    build(){
        column().titleText()
    }
}

注意:组件外定义多加一个function

总结:

1、布局容器公共样式可以用styles来进行定义,即通用属性和通用事件 2、公共样式提取放在组件内部,也可以放在组件外部,但是必须在同一个文件中 3、可以理解@styles定义公共样式实际上抽取函数出来,但是不能传递参数

@Extend装饰器

作用:对组件的样式或者事件进行扩展。使用这个装饰器可以对原生组件进行重定义,然后在页面中复用,类似于@Styles的效果,但必须指定对那个原生组件进行扩展。

[@Extend](/user/Extend)(Text) textStyles(){
    .fontSize(16)
    .fontColor(Color.Red)
    
[@Extend](/user/Extend)(Line) lineStyles(value:string='100%'){
    .width(value)
    .height(1)
    .backgroundColor('red')
}

总结:

1、@Extend进行样式扩展,针对指定的组件进行样式封装、重构 2、@Extend解决@Styles无法传递参数的问题

@Link@Prop装饰器

作用:

@Prop装饰的变量和父组件建立单向的同步关系。

@Link装饰的变量与其父组件中的数据源共享相同的值。

总结:

1、@Link@Prop只能在@Component组件中使用,不能再@Entry组件中使用 2、@Link@Prop定义变量,可以默认不初始化,本来代表接收外部数据 3、@Prop定义参数,可以进行修改,只对本组件生效。@Link可以进行修改,不管都组件还是子组件数据都是同步变化。

@Provide装饰器和@Consume装饰器

作用:应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。

两种绑定方式

// 通过相同的变量名绑定
[@Provide](/user/Provide) age: number = 0;
[@Consume](/user/Consume) age: number;

// 通过相同的变量别名绑定
// 通过别名绑定的时候,[@Provide](/user/Provide)/[@Consume](/user/Consume)的参数key必须为string类型
[@Provide](/user/Provide)('a') id: number = 0;
[@Consume](/user/Consume)('a') age: number;

总结:

1、@Provide@Consume通过相同的变量名或者相同的变量别名绑定时 2、@Provide装饰的变量和@Consume装饰的变量是一对多的关系 3、不允许在同一个自定义组件内,包括其子组件中声明多个同名或者同别名的@Provide装饰的变量,@Provide的属性名或别名需要唯一且确定

@Observed装饰器和@ObjectLink装饰器

作用:以上装饰器(包括@State@Prop@Link@Provide@Consume装饰器)仅仅只能观察到第一层的变化,但是在实际应用中,对于多层嵌套的情况,如二维数组,数组项class或者class的属性是class他们的二层属性变化是无法观察到的,就需要用到以上装饰器。

总结:

1、@ObjectLink装饰的变量不能本地初始化,仅能通过构造参数从父组件传入初始值。且@ObjectLink装饰的变量是只读的,不能被赋值。如果需要对@ObjectLink装饰的变量进行整体替换,可以在父组件对其进行整体替换。 2、@ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。 3、@ObjectLink装饰的变量类型需要为显式的被@Observed装饰的类

对象数组:

export class Pet{
  id:string=''
  name:string=''
  type:string=''

  constructor(id:string,name:string,type:string) {
    this.id=id
    this.name=name
    this.type=type
  }
}

[@Observed](/user/Observed)
export class Student{
  id:string=''
  name:string=''
  pet:Pet

  constructor(id: string, name: string, pet: Pet) {
    this.id = id
    this.name = name
    this.pet = pet
  }

}
import { Pet, Student } from './StudentModel'
import { JSON } from '@kit.ArkTS'
import { ObjectLinkList } from './ObjectLinkList'


[@Entry](/user/Entry)
[@Component](/user/Component)
struct Index {
  [@State](/user/State) stu: Array<Student>=[
    new Student('1','xiaowang',new Pet('001','小花花','金毛')),
    new Student('2','xiaohua','旺财','拉布拉多')
  ]

  aboutToAppear(): void {
    console.log(JSON.stringify(this.stu))
  }

  build() {
    Column() {
      ForEach(this.stu,(item:Student,index:number)=>{
        ObjectLinkList({item:item})
      },(item:Student)=>item.id)
    }
    .height('100%')
    .width('100%')
  }
}
import { Student } from "./StudentModel"

[@Component](/user/Component)
export struct ObjectLinkList{
  [@ObjectLink](/user/ObjectLink) item:Student
  build() {
    Column(){
      Text(`学生名字:${this.item.name},学生宠物名字:${this.item.pet.name}`)
        .fontColor(Color.Brown)
        .fontSize(20)
      Button('修改学生名字')
        .onClick(()=>{
          this.item.name='默认名字'
        })
    }.height('100%').width('100%')

  }
}

子组件接收得数据就是要监听得那个对象 ObjectLink配合Observed就能实现对指定得这个对象进行深度监听

嵌套对象:

[@Observed](/user/Observed)
export class Pet{
  id:string=''
  name:string=''
  type:string=''

  constructor(id:string,name:string,type:string) {
    this.id=id
    this.name=name
    this.type=type
  }
}

[@Observed](/user/Observed)
export class Student{
  id:string=''
  name:string=''
  pet:Pet

  constructor(id: string, name: string, pet: Pet) {
    this.id = id
    this.name = name
    this.pet = pet
  }

}
import { Pet, Student } from './StudentModel'
import { JSON } from '@kit.ArkTS'
import { ObserverChildren } from './ObjectLinkList'


[@Entry](/user/Entry)
[@Component](/user/Component)
struct Index {
  [@State](/user/State) stu:Student=new Student('1','xiaowang',new Pet('001','小花花','金毛'))

  aboutToAppear(): void {
    console.log(JSON.stringify(this.stu))
  }

  build() {
    Column() {
      Text(`学生得信息为${JSON.stringify(this.stu)}`)
        .fontSize(26)
      Button('修改学生名字')
        .onClick(()=>{
          this.stu.pet.name='旺财一号'
        })
      ObserverChildren({pet:this.stu.pet})
    }
    .height('100%')
    .width('100%')
  }
}
import { Pet } from "./StudentModel"

[@Component](/user/Component)
export struct ObserverChildren{
  [@ObjectLink](/user/ObjectLink) pet:Pet
  build() {
    Column(){
      Text(`宠物得信息:${this.pet.name}`)
        .fontColor(Color.Brown)
        .fontSize(20)
      Button('修改宠物名字')
        .onClick(()=>{
          this.pet.name='旺财'
        })
    }.height('100%').width('100%')

  }
}

总结:如果页面上只是渲染嵌套对象,那我们无需进行干预,直接渲染就可以了。但是如果要针对嵌套对象进行修改,一定创建一个子组件,将这个对象传递给子组件专门进行页面渲染以及修改。也需要给model数据约束增加@Observered@ObjectLink来接收修改对象。

@Watch

作用:@watch可以实现监听页面某一个属性。当这个值发生变化,默认会执行一段函数。

总结:

使用限制:

1、@watch监控状态变量。进来不要出现循环引用对象或者变量 2、不要在@watch的监听函数中执行耗时的业务,引起性能问题 3、不建议在@watch监听中使用await和async 4、@watch监控属性回调函数必须是普通函数,不能用箭头函数


更多关于HarmonyOS鸿蒙Next中AskTs中的装饰器的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS鸿蒙Next中AskTs中的装饰器的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,AskTs装饰器主要用于增强TypeScript类的功能。它允许开发者在类或方法上添加元数据,从而实现依赖注入、AOP(面向切面编程)等高级功能。通过使用装饰器,开发者可以更灵活地管理和扩展代码结构,提升代码的可读性和可维护性。AskTs装饰器通常与框架的其他特性结合使用,以简化开发流程并提高应用性能。

回到顶部