HarmonyOS 鸿蒙Next中如何使用自定义属性装饰器限制属性的赋值

HarmonyOS 鸿蒙Next中如何使用自定义属性装饰器限制属性的赋值

最近了解到鸿蒙开放了自定义装饰,不太会用,想请教下下面的例子里面为什么不会触发setter的校验,另外有arkts装饰器的详细教程吗,求传送门

function positiveNumber(target: Object, propertyKey: string) {
  let value: number = 0;
  const getter = () => {
    return value;
  };
  const setter = (newValue: number) => {
    if (newValue < 0) {
      throw new Error(`${propertyKey} must be a positive number.`);
    }
    value = newValue;
  };

  target.constructor.prototype[propertyKey] = {
    get: getter,
    set: setter,
    value: value
  }
}

class MyModel {
  @positiveNumber
  age: number = 20;
}

const myModel = new MyModel();
myModel.age = -1;

更多关于HarmonyOS 鸿蒙Next中如何使用自定义属性装饰器限制属性的赋值的实战教程也可以访问 https://www.itying.com/category-93-b0.html

5 回复

【背景知识】

ArkTS本身没有自定义装饰器相关的内容,所以我们只能使用TS的自定义装饰器,而且HarmonyOS只支持TS5.0之前的自定义装饰器语法。参考如何在ArkTS中实现自定义装饰器能力

【解决方案】

以下是类装饰器、属性装饰器、方法装饰器、参数装饰器的简单示例:

// 类装饰器
function TestClassDecorator(target: Function) {}
// 属性装饰器
function TestMemberDecorator(target: testClass, memberName: String) {}
// 方法装饰器
function TestFunDecorator(target: testClass, propertyName: String, descriptor: PropertyDescriptor) {}
// 参数装饰器
function TestArgDecorator(target: Function, methodName: String, paramIndex: Number) {}

@TestClassDecorator
class testClass {
  @TestMemberDecorator
  count: number = 123;

  @TestFunDecorator
  TestFun(@TestArgDecorator param: string) {}
}

【总结】

ArkTS在TS基本语法风格的基础上,进一步通过规范强化静态检查和分析,使得在程序运行之前的开发期能检测出更多错误,提升代码的健壮性,并实现更好的性能,因此从TS迁移过来的代码需要进行人工检测修复,无法直接复用。

更多关于HarmonyOS 鸿蒙Next中如何使用自定义属性装饰器限制属性的赋值的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


通过target.constructor.prototype直接修改原型链属性,导致访问器和实例属性冲突

类属性初始化 age: number = 20 直接为实例属性赋值,未触发装饰器中的 setter 逻辑。

通过 myModel.age = -1 赋值时,实际访问的是实例属性而非装饰器定义的访问器

楼主代码中通过直接修改target.constructor.prototype的方式实现属性拦截,这种方式在ArkTS中可能无法正常触发响应式更新。ArkTS的装饰器需要遵循TypeScript装饰器规范,应当通过返回属性描述符的方式进行属性拦截。

ArkTS对装饰器的支持存在类型限制。若需要实现属性校验,可以结合@Observed@ObjectLink响应式装饰器使用。

实现属性校验方式

1—使用ArkTS内置状态管理装饰器

[@Observed](/user/Observed)

class MyModel {

  @Monitor // V2状态管理装饰器支持变化监听
  age: number = 20;

}

@ComponentV2
struct MyComponent {

  @Local model: MyModel = new MyModel();

  build() {
    Button('Change Age')
      .onClick(() => {
        if (this.model.age < 0) {
          console.error('Age must be positive!')
          return
        }
        this.model.age = -1 // 触发校验逻辑
      })
  }
}

2—自定义装饰器的实现

function positiveNumber(target: any, key: string) {
  let value = target[key];
  const getter = () => value;
  const setter = (newVal: number) => {
    if (newVal < 0) throw new Error(`${key} must be positive`);
    value = newVal;
  };
  Object.defineProperty(target, key, {
    get: getter,
    set: setter,
    enumerable: true,
    configurable: true
  });
}

在HarmonyOS Next中,使用自定义属性装饰器限制属性赋值可通过@Observed@Prop装饰器实现。首先用@Observed装饰类,再用@Prop装饰属性,结合aboutToChange回调进行验证。示例:

@Observed
class User {
  @Prop aboutToChange(newValue: string): boolean {
    return newValue.length <= 10; // 限制长度不超过10
  }
  name: string = '';
}

当赋值超过长度限制时,系统会自动阻止赋值。也可使用@Link实现父子组件间的双向绑定校验。

在HarmonyOS Next中使用装饰器时,你的代码有几个需要注意的地方:

  1. 装饰器实现方式问题:当前写法没有正确覆盖原属性的getter/setter。ArkTS装饰器应该直接修改属性描述符:
function positiveNumber(target: any, propertyKey: string) {
  let value = target[propertyKey];
  
  Object.defineProperty(target, propertyKey, {
    get: () => value,
    set: (newValue: number) => {
      if (newValue < 0) {
        throw new Error(`${propertyKey} must be positive`);
      }
      value = newValue;
    },
    enumerable: true,
    configurable: true
  });
}
  1. 装饰器应用时机:ArkTS装饰器在类定义时就会执行,而你的实现方式会导致原型链访问问题。

  2. 关于教程:目前官方文档中ArkTS装饰器部分可以参考华为开发者文档中的"ArkTS语言规范"章节,特别是"装饰器"相关内容。

这个修改后的版本会正确触发校验,当赋值为负数时会抛出错误。注意ArkTS对装饰器的支持与标准TypeScript有些差异,建议在实际开发中多进行测试验证。

回到顶部