ArkTs学习之ArkTS装饰器@Styles装饰器 @Extend装饰器, AttributeModifier 机制(三)

ArkUI的开发过程中,样式的复用和管理对于提升代码的可维护性和开发效率至关重要。为此,ArkUI提供了多种机制来实现样式的复用和扩展,主要包括:@Styles@Extend装饰器,以及AttributeModifier机制。本文将基于最新的ArkUI版本,详细探讨这三者的应用场景、使用方法及其优缺点。

一. @Styles 装饰器

1. 概述

@Styles装饰器用于将多条样式设置提炼成一个方法,方便在组件声明时直接调用,实现样式的快速定义和复用。它主要适用于通用属性和事件的复用。

2. 使用规则

  • 定义位置:可以在组件内或全局定义。全局定义时,需在方法名前添加function关键字;组件内定义时,则不需要。
  • 参数支持:@Styles方法不支持参数传递。
  • 访问组件状态:定义在组件内的@Styles方法可以通过this访问组件的常量和状态变量,并可以在方法内通过事件来改变状态变量的值。
  • 访问范围,在全局定义时需在方法名前添加 function 关键字,且只能在当前文件内使用,不支持 export。若想实现 export 功能,推荐使用 AttributeModifier。

3. 示例

以下示例展示了如何在全局和组件内定义和使用@Styles装饰器:

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

@Entry
@Component
struct FancyUse {
  /** 成员变量 */
  @State heightValue: number = 100
  
  /** 构建函数 */
  build() {
    Column({ space: 10 }) {
      // 使用全局的@Styles封装的样式
      Text('FancyA')
        .globalFancy()
        .fontSize(30)
      // 使用组件内的@Styles封装的样式
      Text('FancyB')
        .fancy()
        .fontSize(30)
    }
  }

  //🌾:组件内定义的@Styles封装的样式
  @Styles
  fancy() {
    .width(200)
    .height(this.heightValue)
    .backgroundColor(Color.Yellow)
    .onClick(() => {
      this.heightValue = 200
    })
  }
}

在上述代码中,globalFancy是在全局定义的样式方法,而fancy是在组件内定义的样式方法。需要注意的是,组件内的@Styles优先级高于全局定义的同名@Styles

二. @Extend 装饰器

1. 概述

@Extend装饰器用于扩展原生组件的样式,支持封装指定组件的私有属性和事件。与@Styles不同,@Extend支持参数传递,提供了更大的灵活性。

2. 使用规则

  • 定义位置:仅支持在全局定义,不支持在组件内部定义。
  • 参数支持:@Extend方法支持参数传递,参数可以是函数或状态变量。当状态变量改变时,UI会自动刷新渲染。
  • 方法调用:可以在@Extend方法内调用其他预定义的@Extend方法,实现样式的组合和复用。
  • 访问范围:同样存在局限性,它也是编译期处理,不支持跨文件的导出复用,不支持 export

3. 示例

以下示例展示了如何使用@Extend装饰器定义和应用样式:

//🌾:定义一个扩展Text组件的样式方法
@Extend(Text)
function fancyText(weightValue: number, color: Color) {
  .fontStyle(FontStyle.Italic)
  .fontWeight(weightValue)
  .backgroundColor(color)
}

@Entry
@Component
struct FancyUse {
  /** 成员变量 */
  @State label: string = 'Hello World'

  /** 构建函数 */
  build() {
    Row({ space: 10 }) {
      Text(`${this.label}`)
        .fancyText(100, Color.Blue)
      Text(`${this.label}`)
        .fancyText(200, Color.Pink)
      Text(`${this.label}`)
        .fancyText(300, Color.Orange)
    }.margin('20%')
  }
}

在上述代码中,fancyText方法扩展了Text组件的样式,并支持通过参数动态设置字体粗细和背景颜色。

三. AttributeModifier 机制

虽然@Styles@Extend装饰器提供了样式复用的能力,但它们存在一些限制:

  • 跨文件复用:由于是编译期处理,这些装饰器不支持跨文件的导出和复用。
  • 动态属性设置:对于属性的设置,无法支持复杂的业务逻辑,只能通过三元表达式对所有可能设置的属性进行全量设置,效率较低。

为了解决上述问题,ArkUI引入了AttributeModifier机制。

1. 概述

AttributeModifier是一种自定义扩展机制,允许开发者在运行时动态地修改组件的属性和样式。它支持跨文件的导出和复用,并且可以包含复杂的业务逻辑,动态决定是否设置某些属性。

2. 使用规则

  • 定义:通过实现AttributeModifier接口,定义自定义的属性修改器。
  • 应用:在组件中,通过use方法应用自定义的属性修改器。

3. 应用场景

在需要动态控制组件属性、进行复杂样式逻辑处理以及跨文件共享样式和属性设置时,AttributeModifier 都能大显身手。比如在一个电商应用中,根据商品的不同状态(如热销、新品、折扣等)动态设置商品展示组件的样式和属性。

以下示例展示了如何定义和使用AttributeModifier

🦋 示例一
//🌾:动态改变按钮的颜色:通过自定义 AttributeModifier 类,实现点击按钮时切换背景颜色。
class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
  isDark: boolean = false
  applyNormalAttribute(instance: ButtonAttribute): void {
    instance.backgroundColor(this.isDark ? Color.Black : Color.Red)
  }
}

@Component
struct attributePressedDemo {
  /** 成员变量 */
  @State modifier: MyButtonModifier = new MyButtonModifier()

  /** 构建函数 */
  build() {
    Column() {
      Button('按钮')
        .attributeModifier(this.modifier)
    }
  }
}
🦋 示例二:
@Component
struct attributeDemo {
  /** 成员变量 */
  @State modifier: MyButtonModifier = new MyButtonModifier()
  /** 构建函数 */
  build() {
    Column() {
      Button('按钮')
        .attributeModifier(this.modifier)
        .onClick(() => {
          this.modifier.isDark = !this.modifier.isDark
        })
    }
  }
}

//🌾:分别设置普通状态和按下状态颜色:利用 AttributeModifier 提供的 applyPressedAttribute 方法,实现按下按钮时背景颜色变化。
class MyButtonModifier implements AttributeModifier<ButtonAttribute> {
  applyNormalAttribute(instance: ButtonAttribute): void {
    instance.backgroundColor(Color.Black)
  }
  applyPressedAttribute(instance: ButtonAttribute): void {
    instance.backgroundColor(Color.Red)
  }
} 

四. AttributeModifier 、@Styles 和 @Extend 对比

与 @Styles 和 @Extend 相比,AttributeModifier 具有更强大的能力和灵活性。它可以让开发者动态设置组件的属性,支持在属性设置时使用 if/else 语法,并且能根据需要使用多态样式设置属性。同时,它支持跨文件导出,弥补了 @Styles 和 @Extend 的不足。

能力@Styles@ExtendAttributeModifier
跨文件导出 不支持 不支持 支持
通用属性设置 支持 支持 支持
通用事件设置 支持 支持 部分支持
组件特有属性设置 不支持 支持 部分支持
组件特有事件设置 不支持 支持 部分支持
参数传递 不支持 支持 支持
多态样式 支持 不支持 支持
业务逻辑 不支持 不支持 支持

可以看出,与@Styles和@Extend相比,AttributeModifier提供了更强的能力和灵活性,且在持续完善全量的属性和事件设置能力,因此推荐优先使用AttributeModifier。

五. 总结

@Styles 适用于简单的组件样式复用,能提高代码编写效率;@Extend 专注于特定组件的样式扩展;而 AttributeModifier 则以其强大的动态属性设置能力和跨文件支持,在复杂场景下表现出色。在实际开发中,应根据具体需求选择合适的方式,以实现高效、灵活的 ArkUI 应用开发。

posted on 2024-04-01 21:39  梁飞宇  阅读(506)  评论(0)    收藏  举报