HarmonyOS鸿蒙NEXT中装饰器的使用

HarmonyOS鸿蒙NEXT中装饰器的使用 1、@State装饰器、@Prop装饰器、@Link装饰
@State装饰器:使得变量变为状态变量,影响UI(数据变化,UI变化)
@Prop装饰器装饰的变量和父组件建立单向的同步关系 (@Prop修饰的变量,api9不能初始化,api11能初始化)
父组件的@State数据变化,会同步到子组件@Prop,具体用法如下:

//父组件:Parent
[@State](/user/State) num:number = 0
build(){
    Son({num:this.num})
}
//子组件:Son
[@Prop](/user/Prop) num:number

@Link装饰器装饰的变量与其父组件中的数据源共享相同的值
父组件的@State数据变化,会同步到子组件@Link数据
子组件@link数据变化,会同步到父组件@State数据具体用法如下:

//父组件:Parent
[@State](/user/State) num:number = 0
build(){
    Son({num:$num})//api9必须使用$,api11开始也可以使用this了
}
//子组件:Son
[@Link](/user/Link) num:number

2、@Provide@Consume装饰器
@Provide@Consume可以通过相同的变量名或者相同的变量别名绑定
@Provide装饰器的变量是在祖先组件中,可以理解为被“提供”给后代的状态变量。@Consume装饰的变量是在后代组件中,去“消费”数据
特点:@Provide@Consume可以通过相同的变量名或者相同的变量别名绑定

// 通过相同的变量名绑定
[@Provide](/user/Provide) a: number = 0; //祖先组件中定义
[@Consume](/user/Consume) a: number;  //子孙组件中定义

// 通过相同的变量别名绑定
[@Provide](/user/Provide)('a') b: number = 0;//参数即为别名
[@Consume](/user/Consume)('a') c: number;

3、@ObjectLink@Observed
@ObjectLink@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:
@Observed装饰的类,可以被观察到属性的变化;
子组件中@ObjectLink装饰器装饰的状态变量用于接收@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也需要被@Observed装饰。
单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。
限制条件:

  • 使用@Observed装饰class会改变class原始的原型链,@Observed和其他类装饰器装饰同一个class可能会带来问题。
  • @ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。
  • @ObjectLink装饰的变量类型需要为显式的被@Observed装饰的类,如果未指定类型,或其不是@Observed装饰的class,编译期会报错。
[@Observed](/user/Observed)
class Info {
  count: number;
  constructor(count: number) {
    this.count = count;
  }
}
class Test {
  msg: number;

  constructor(msg: number) {
    this.msg = msg;
  }
}
// 错误写法,编译报错
[@ObjectLink](/user/ObjectLink) count;
[@ObjectLink](/user/ObjectLink) test: Test;
// 正确写法
[@ObjectLink](/user/ObjectLink) count: Info;

4、@Watch
@Watch应用于对状态变量的监听。如果开发者需要关注某个状态变量的值是否改变,可以使用@Watch为状态变量设置回调函数。
@Watch用于监听状态变量的变化,当状态变量变化时,@Watch的回调方法将被调用

[@Component](/user/Component)
struct TotalView {
  [@Prop](/user/Prop) [@Watch](/user/Watch)('onCountUpdated') count: number = 0;
  [@State](/user/State) total: number = 0;
  // 该函数是自定义组件的成员函数
  // [@Watch](/user/Watch) 回调
  // propName是被watch的属性名
  // 多个状态绑定同一个[@Watch](/user/Watch)回调时,通过propName区分到底是哪个状态改变了
  onCountUpdated(propName: string): void {
    this.total += this.count;
  }

  build() {
    Text(`Total: ${this.total}`)
  }
}

[@Entry](/user/Entry)
[@Component](/user/Component)
struct CountModifier {
  [@State](/user/State) count: number = 0;

  build() {
    Column() {
      Button('add to basket')
        .onClick(() => {
          this.count++
        })
      TotalView({ count: this.count })
    }
  }
}

5、@Styles@Extend@Builder
@Styles装饰器:定义组件重用样式 (多个组件通用的样式)
@Styles装饰器,用于封装重复的通用样式代码。
如果多个不同类型的组件,有着相同的样式,例如宽高,背景色,字体大小。那么就可以将这下相同的样式代码抽取到一个@Styles装饰器修饰的方法中,供大家复用。
支持全局和局部定义:

// 全局
[@Styles](/user/Styles) functionName() { ... } //styles方法不能调用另一个styles方法***
// 在组件内
[@Component](/user/Component)
struct FancyUse {
  [@Styles](/user/Styles) fancy() {
    .height(100)
  }
}

@Extend装饰器:定义扩展组件样式 (某一种组件自己的样式,私有属性)
@Extend,用于扩展原生组件样式。
如果同一类型的组件,有着很多相同的样式,例如按钮的类型,点击事件等。那么就可以将这些重复代码,抽过去到一个@Extend装饰器修饰的方法中,供此组件使用。
仅支持全局定义:(因为它相当于是给所有的此类组件使用)

// [@Extend](/user/Extend)(Text)可以支持Text的私有属性fontColor
[@Extend](/user/Extend)(Text) function fancy () {
  .fontColor(Color.Red)
}
// superFancyText可以调用预定义的fancy
[@Extend](/user/Extend)(Text) function superFancyText(size:number) { //Extend方法可以调用另一个Extend方法
    .fontSize(size)
    .fancy()
}

@Builder装饰器:自定义构建函数
@Builder装饰器,用于封装重复的,复杂UI结构代码,例如List中的ListItem的布局结构,一般比较复杂就可以抽取到@Builder装饰的函数中
@Builder所装饰的函数遵循build()函数语法规则,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。
支持全局定义和局部定义:

//既然调用是通过this调用,那么说明是在组件内部定义
//组件内部定义不需要关键字function
[@Builder](/user/Builder) MyBuilderFunction() { ... }
//全局定义
MyGlobalBuilderFunction()

@BuilderParam装饰器:引用@Builder函数
当开发者创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作。若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。
为解决此问题,ArkUI引入了@BuilderParam装饰器,该装饰器用于声明任意UI描述的一个元素,类似slot占位符。
使得自定义组件更加灵活
代码:

[@Component](/user/Component)
struct Child {
  [@Builder](/user/Builder) customBuilder() {}
  // 使用父组件[@Builder](/user/Builder)装饰的方法初始化子组件[@BuilderParam](/user/BuilderParam)
  [@BuilderParam](/user/BuilderParam) customBuilderParam: () => void = this.customBuilder;

  build() {
    Column() {
      this.customBuilderParam()
    }
  }
}

[@Entry](/user/Entry)
[@Component](/user/Component)
struct Parent {
  [@Builder](/user/Builder) componentBuilder() {
    Text(`Parent builder `)
  }

  build() {
    Column() {
      Child({ customBuilderParam: this.componentBuilder })
    }
  }
}

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

2 回复

在HarmonyOS鸿蒙NEXT中,装饰器是一种用于增强或修改类、方法、属性等行为的语法特性。装饰器通过@符号来标识,可以应用于类、方法、属性或参数上。鸿蒙NEXT中的装饰器主要用于实现一些通用的功能,如日志记录、权限检查、数据绑定等。

装饰器的使用场景包括:

  1. 类装饰器:用于修改类的行为,如添加元数据、扩展类的功能等。
  2. 方法装饰器:用于在方法执行前后添加额外的逻辑,如日志记录、权限验证等。
  3. 属性装饰器:用于对类属性进行拦截或修改,如数据绑定、属性校验等。
  4. 参数装饰器:用于对方法的参数进行拦截或修改,如参数校验、参数注入等。

鸿蒙NEXT中的装饰器通过@符号来标识,例如:

@log
class MyClass {
  @readonly
  myProperty: string;

  @validate
  myMethod(@inject param: string) {
    // 方法逻辑
  }
}

在这个例子中,@log是类装饰器,@readonly是属性装饰器,@validate是方法装饰器,@inject是参数装饰器。

装饰器的实现通常是一个函数,该函数接收目标对象、属性名或参数索引等信息,并返回一个修改后的对象或执行某些逻辑。鸿蒙NEXT中的装饰器语法与TypeScript中的装饰器类似,但具体实现可能有所不同,以适应鸿蒙系统的特性和需求。

总结:鸿蒙NEXT中的装饰器是一种强大的语法特性,用于增强或修改类、方法、属性等的行为,适用于日志记录、权限检查、数据绑定等场景。

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


在HarmonyOS鸿蒙NEXT中,装饰器是一种用于修改类、方法或属性的特殊语法。通过在类、方法或属性前添加@符号和装饰器函数,开发者可以扩展或修改其行为。常见场景包括日志记录、权限校验、数据绑定等。例如:

function log(target, name, descriptor) {
    const original = descriptor.value;
    descriptor.value = function(...args) {
        console.log(`Calling ${name} with`, args);
        return original.apply(this, args);
    };
    return descriptor;
}

class MyClass {
    @log
    myMethod() {
        // 方法逻辑
    }
}

上述代码通过@log装饰器在myMethod执行前后添加日志记录功能。鸿蒙NEXT的装饰器机制与标准JavaScript/TypeScript一致,便于开发者快速上手。

回到顶部