HarmonyOS鸿蒙的装饰器有哪些及其作用?

217 阅读5分钟

@Builder装饰器:自定义构建函数

定义:

@Builder是一种轻量的UI复用机制,开发者可以将重复使用的UI元素抽象成一个方法。

简而言之,我们将@Builder装饰的函数也称为“自定义构建函数”。

使用:

@Builder装饰器有两种使用方式,分别是自定义组件内部的私有自定义构建函数全局自定义构建函数

例子:

私有自定义构建函数

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

全局自定义构建函数

@Builder
function showTextBuilder() {
  Text('Hello World')
    .fontSize(30)
    .fontWeight(FontWeight.Bold)
}

@Entry
@Component
struct BuilderDemo {
  build() {
    Column() {
      showTextBuilder()
    }
  }
}

@LocalBuilder装饰器: 维持组件父子关系

定义:

为了解决组件的父子关系和状态管理的父子关系保持一致的问题,引入@LocalBuilder装饰器。@LocalBuilder拥有和局部@Builder相同的功能,且比局部@Builder能够更好的确定组件的父子关系和状态管理的父子关系。

使用:

  • 允许在自定义组件内定义一个或多个@LocalBuilder方法,该方法被认为是该组件的私有、特殊类型的成员函数。
  • 自定义构建函数可以在所属组件的build方法和其他自定义构建函数中调用,但不允许在组件外调用。
  • 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不是参数传递。

限制条件:

  • @LocalBuilder只能在所属组件内声明,不允许全局声明。
  • @LocalBuilder不能被内置装饰器和自定义装饰器使用。
  • 自定义组件内的静态方法不能和@LocalBuilder一起使用。

@LocalBuilder和局部@Builder使用区别

@Builder方法引用传参时,为了改变this指向,使用bind(this)后,会导致组件的父子关系和状态管理的父子关系不一致,使用@LocalBuilder不会改变组件的父子关系。

举例:

class ReferenceType {
  paramString: string = '';
}

@Entry
@Component
struct Parent {
  @State variableValue: string = 'Hello World';

  @LocalBuilder
  citeLocalBuilder(params: ReferenceType) {
    Row() {
      Text(`UseStateVarByReference: ${params.paramString}`)
    }
  };

  build() {
    Column() {
      this.citeLocalBuilder({ paramString: this.variableValue })
      Button('Click me').onClick(() => {
        this.variableValue = 'Hi World';
      })
    }
  }
}

@BuilderParam装饰器:引用@Builder函数

定义:

@BuilderParam用来装饰指向@Builder方法的变量。该装饰器用于声明任意UI描述的一个元素,类似slot占位符。

使用:

@Component
struct Child {
  @Builder customBuilder() {};
  @BuilderParam customBuilderParam: () => void = this.customBuilder;

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

@Preview
@Entry
@Component
struct BuilderParamPage {
  @Builder componentBuilder() {
    Text(`Parent builder `)
  }

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

@Styles装饰器:样式复用

使用说明

  • 当前@Styles仅支持通用属性通用事件
  • @Styles可以定义在组件内或全局,在全局定义时需在方法名前面添加function关键字。
  • 只能在当前文件内使用,不支持export。如果想实现export功能,推荐使用AttributeModifier
// 全局
@Styles function functionName() { ... }

// 在组件内
@Component
struct FancyUse {
  @Styles fancy() {
    .height(100)
  }
}

例子:

// 定义在全局的@Styles封装的样式
@Styles function globalFancy  () {
  .width(150)
  .height(100)
  .backgroundColor(Color.Pink)
}

@Entry
@Component
struct FancyUse {
  @State heightValue: number = 100;
  // 定义在组件内的@Styles封装的样式
  @Styles fancy() {
    .width(200)
    .height(this.heightValue)
    .backgroundColor(Color.Yellow)
    .onClick(() => {
      this.heightValue = 200
    })
  }

  build() {
    Column({ space: 10 }) {
      // 使用全局的@Styles封装的样式
      Text('FancyA')
        .globalFancy()
        .fontSize(30)
      // 使用组件内的@Styles封装的样式
      Text('FancyB')
        .fancy()
        .fontSize(30)
    }
  }
}

@Extend装饰器:扩展组件样式

@Extend,用于扩展原生组件样式。

限制条件

  • 和@Styles不同,@Extend仅支持在全局定义,不支持在组件内部定义。
  • 只能在当前文件内使用,不支持export。
@Extend(Text) function fancy (fontSize: number) {
  .fontSize(fontSize)
}

@Entry
@Component
struct FancyUse {

  build() {
    Row({ space: 10 }) {
      Text('Fancy')
        .fancy(16)
    }
  }
}

@AnimatableExtend装饰器:定义可动画属性

如果一个属性方法在animation属性前调用,改变这个属性的值可以使animation属性的动画生效,这个属性称为可动画属性。比如height、width、backgroundColor、translate属性,和Text组件的fontSize属性等。

使用说明

@AnimatableExtend(UIComponentName) function functionName(value: typeName) { 
  .propertyName(value)
}

使用:

@AnimatableExtend(Text)
function animatableWidth(width: number) {
  .width(width)
}

@Entry
@Component
struct AnimatablePropertyExample {
  @State textWidth: number = 80;

  build() {
    Column() {
      Text("AnimatableProperty")
        .animatableWidth(this.textWidth)
        .animation({ duration: 2000, curve: Curve.Ease })
      Button("Play")
        .onClick(() => {
          this.textWidth = this.textWidth == 80 ? 160 : 80;
        })
    }.width("100%")
    .padding(10)
  }
}

@Require装饰器:校验构造传参

当@Require装饰器和@Prop、@State、@Provide、@BuilderParam、普通变量结合使用时,必须在构造时传参。

举例:

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';

  @Builder buildTest() {
    Row() {
      Text('Hello, world')
        .fontSize(30)
    }
  }

  build() {
    Row() {
      Child({ regular_value: this.message, state_value: this.message, provide_value: this.message, initMessage: this.message, message: this.message,
        buildTest: this.buildTest, initBuildTest: this.buildTest })
    }
  }
}

@Component
struct Child {
  @Builder buildFunction() {
    Column() {
      Text('initBuilderParam')
        .fontSize(30)
    }
  }
  @Require regular_value: string = 'Hello';
  @Require @State state_value: string = "Hello";
  @Require @Provide provide_value: string = "Hello";
  @Require @BuilderParam buildTest: () => void;
  @Require @BuilderParam initBuildTest: () => void = this.buildFunction;
  @Require @Prop initMessage: string = 'Hello';
  @Require @Prop message: string;

  build() {
    Column() {
      Text(this.initMessage)
        .fontSize(30)
      Text(this.message)
        .fontSize(30)
      this.initBuildTest();
      this.buildTest();
    }
    .width('100%')
    .height('100%')
  }
}

@Reusable装饰器:组件复用

@Reusable适用自定义组件,与@Component结合使用,标记为@Reusable的自定义组件从组件树上被移除时,组件和其对应的JSView对象都会被放入复用缓存中,后续创建新自定义组件节点时,会复用缓存区中的节点,节约组件重新创建的时间。

限制条件

  • @Reusable装饰器仅用于自定义组件。
  • ComponentContent不支持传入@Reusable装饰器装饰的自定义组件。
  • @Reusable装饰器不支持嵌套使用,存在增加内存和不方便维护的问题;

使用场景

  • 列表滚动:当应用需要展示大量数据的列表,频繁创建和销毁列表项可能导致性能问题。在这种情况下,使用列表组件的组件复用机制可以提高滚动的流畅度。
  • 动态布局更新:如果应用中的界面需要频繁地进行布局更新,重复创建和销毁视图可能导致频繁的布局计算,影响帧率。在这种情况下,使用组件复用可以提高性能。
  • 频繁创建和销毁数据项的视图场景下。使用组件复用可以重用已创建的视图,只更新数据的内容,减少视图的创建和销毁,能有效提高性能。