【ArkTS-装饰器】

ArkTS-装饰器

  • [■ ArkTS 装饰器](#■ ArkTS 装饰器)
    • [■ @Entry 页面的生命周期](#■ @Entry 页面的生命周期)
    • [■ @Component 自定义组件](#■ @Component 自定义组件)
      • [■ 1. Component装饰的struct称为UI组件。主要特征:](#■ 1. Component装饰的struct称为UI组件。主要特征:)
      • [■ 2. component内部还可以调用另外一个component 示例](#■ 2. component内部还可以调用另外一个component 示例)
    • [■ @Builder装饰器: 自定义构建函数可复用 UI 片段](#■ @Builder装饰器: 自定义构建函数可复用 UI 片段)
      • [■ 简单的无参数@Builder](#■ 简单的无参数@Builder)
      • [■ 带参数的@Builder](#■ 带参数的@Builder)
      • [■ 包含逻辑的@Builder](#■ 包含逻辑的@Builder)
      • [■ 包含循环的@Builder](#■ 包含循环的@Builder)
      • [■ 使用列表@Builder](#■ 使用列表@Builder)
      • [■ 全局定义@Builder](#■ 全局定义@Builder)
      • [■ @Builder 与组件交互](#■ @Builder 与组件交互)
      • [■ @BuilderParam:Builder 作为参数](#■ @BuilderParam:Builder 作为参数)
      • [■ @Builder 与状态管理](#■ @Builder 与状态管理)
    • [■ 传递参数](#■ 传递参数)
      • [■ 1. 按值传递参数](#■ 1. 按值传递参数)
      • [■ 2. 按引用传递参数](#■ 2. 按引用传递参数)
    • [■ @State状态装饰器](#■ @State状态装饰器)
      • [■ 示例 -状态改变时 UI会发生对应的渲染改变](#■ 示例 -状态改变时 UI会发生对应的渲染改变)
    • [■ @Prop装饰器:父子单向同步](#■ @Prop装饰器:父子单向同步)
      • [■ 示例功能说明:](#■ 示例功能说明:)
    • [■ @Track装饰器:// 使用@Track装饰器标记需要跟踪的字段](#■ @Track装饰器:// 使用@Track装饰器标记需要跟踪的字段)
    • [■ @Observed //定义一个被观察的类,](#■ @Observed //定义一个被观察的类,)
    • [■ @Link 建立双向数据绑定,任何一方对数据的修改都会同步到另一方](#■ @Link 建立双向数据绑定,任何一方对数据的修改都会同步到另一方)
    • [■ @ObjectLink 与父组件共享同一对象引用](#■ @ObjectLink 与父组件共享同一对象引用)
    • [■ @Watch](#■ @Watch)
    • [■ @LocalBuilder装饰器: 维持组件父子关系](#■ @LocalBuilder装饰器: 维持组件父子关系)
    • [■ @AnimatableExtend装饰器:定义可动画属性](#■ @AnimatableExtend装饰器:定义可动画属性)
    • [■ @Require装饰器:校验构造传参](#■ @Require装饰器:校验构造传参)
    • [■ @Reusable装饰器:组件复用](#■ @Reusable装饰器:组件复用)
    • [■ @Watch装饰器:状态变量更改通知](#■ @Watch装饰器:状态变量更改通知)
    • [■ @Styles装饰器:定义组件重用样式](#■ @Styles装饰器:定义组件重用样式)
    • [■ @Extend装饰器:定义扩展组件样式](#■ @Extend装饰器:定义扩展组件样式)
    • [■ @Monitor装饰器:状态变量修改监听](#■ @Monitor装饰器:状态变量修改监听)
    • [■ @Param:组件外部输入](#■ @Param:组件外部输入)
    • [■ @Once:初始化同步一次](#■ @Once:初始化同步一次)
    • [■ @Event装饰器:规范组件输出](#■ @Event装饰器:规范组件输出)
    • [■ @Provider装饰器和 @Consumer装饰器:跨组件层级双向同步](#■ @Provider装饰器和 @Consumer装饰器:跨组件层级双向同步)
    • [■ @Type装饰器:标记类属性的类型](#■ @Type装饰器:标记类属性的类型)

■ ArkTS 装饰器

■ @Entry 页面的生命周期

一个页面有且仅有一个@Entry入口。

■ @Component 自定义组件

HarmonyOS的生命周期可以分为 @Compnent的生命周期和 @Entry的生命周期 也就是自定义组件的生命周期和页面的生命周期。

@Component和@Entry,ArkTS通过这两个关键字来装饰struct声明的数据结构,这个过程我们称为自定义组件。

组件内部需要提供一个build函数,我们在该函数体内按照链式调用的方式来描述整个页面的UI布局。

■ 1. Component装饰的struct称为UI组件。主要特征:

  1. 一个页面有且仅有一个@Entry入口。
  2. 一个页面可以包含一个或多个component;
  3. 每个component都必须实现 build 方法来更新UI;
  4. 一个component内部还可以调用另外一个component;

■ 2. component内部还可以调用另外一个component 示例

示例

typescript 复制代码
@Entry       //一个页面有且仅有一个@Entry入口。
@Component   //一个页面可以包含一个或多个component;
struct MainComponent {
  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Text('Black is MainComponent')
        .fontSize(26)
        .fontColor(Color.Black)
        .height(50)
      SubComponent()  //调用
    }
    .width('100%')
    .height('100%')
  }
}

@Component  //一个页面可以包含一个或多个component;
struct SubComponent {
  build() {
    Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
      Text('Red is SubComponent')
        .fontSize(26)
        .fontWeight(500)
        .fontColor(Color.Red)
    }
    .width('100%')
  }
}

■ @Builder装饰器: 自定义构建函数可复用 UI 片段

■ 简单的无参数@Builder

■ 带参数的@Builder

■ 包含逻辑的@Builder

■ 包含循环的@Builder

■ 使用列表@Builder

c 复制代码
@Entry
@Component
struct BuilderExample {
  // 简单的无参数Builder
  @Builder
  simpleTextBuilder() {
    Text('Hello World')
      .fontSize(30)
      .fontWeight(FontWeight.Bold)
      .fontColor(Color.Blue)
  }

  // 带参数的Builder
  @Builder
  parameterizedBuilder(text: string, size: number, color: Color) {
    Text(text)
      .fontSize(size)
      .fontColor(color)
      .fontWeight(FontWeight.Medium)
  }

  // 包含逻辑的Builder
  @Builder
  conditionalBuilder(score: number) {
    if (score >= 90) {
      Text('优秀')
        .fontColor(Color.Green)
    } else if (score >= 60) {
      Text('及格')
        .fontColor(Color.Orange)
    } else {
      Text('不及格')
        .fontColor(Color.Red)
    }
  }

  // 包含循环的Builder
  @Builder
  listBuilder(items: string[]) {
    Column() {
      ForEach(items, (item: string) => {
        Text(item)
          .fontSize(16)
          .margin(5)
      })
    }
  }

  build() {
    Column({ space: 20 }) {
      // 使用无参数Builder
      this.simpleTextBuilder()
      
      // 使用带参数Builder
      this.parameterizedBuilder('自定义文本', 24, Color.Red)
      
      Divider()
      
      // 使用条件Builder
      this.conditionalBuilder(85)
      this.conditionalBuilder(55)
      
      Divider()
      
      // 使用列表Builder
      this.listBuilder(['项目1', '项目2', '项目3', '项目4'])
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

■ 全局定义@Builder

c 复制代码
// 全局Builder定义
@Builder
function GlobalCard(title: string, content: string) {
  Column() {
    Text(title)
      .fontSize(20)
      .fontWeight(FontWeight.Bold)
      .margin({ bottom: 10 })

    Text(content)
      .fontSize(16)
      .fontColor(Color.Gray)
  }
  .padding(15)
  .backgroundColor(Color.White)
  .border({ width: 1, color: Color.Gray })
  .borderRadius(8)
  .width('90%')
  .margin({ bottom: 10 })
}

@Entry
@Component
struct GlobalBuilderExample {
  build() {
    Column() {
      Text('全局Builder示例')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 20 })

      // 使用全局Builder
      GlobalCard('标题1', '这是第一个卡片的内容')
      GlobalCard('标题2', '这是第二个卡片的内容,内容可以更长一些')
      GlobalCard('标题3', '第三个卡片的内容')
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .backgroundColor('#F5F5F5')
    .justifyContent(FlexAlign.Start)
  }
}

■ @Builder 与组件交互

c 复制代码
@Entry
@Component
struct InteractiveBuilderExample {
  @State count: number = 0
  @State text: string = '初始文本'

  // Builder访问组件状态
  @Builder
  counterBuilder() {
    Row() {
      Button('减少')
        .onClick(() => {
          this.count--
        })

      Text(`计数: ${this.count}`)
        .fontSize(18)
        .margin(10)

      Button('增加')
        .onClick(() => {
          this.count++
        })
    }
  }

  // Builder访问组件方法
  @Builder
  textInputBuilder() {
    Column() {
      TextInput({ text: this.text })
        .onChange((value: string) => {
          this.text = value
        })
        .width(200)

      Text(`当前文本: ${this.text}`)
        .fontSize(16)
        .margin({ top: 10 })
    }
  }

  build() {
    Column({ space: 20 }) {
      Text('Builder与组件交互示例')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      this.counterBuilder()
      this.textInputBuilder()
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

■ @BuilderParam:Builder 作为参数

  • @BuilderParam 允许将 Builder 作为参数传递给组件,实现高度可定制的 UI:
c 复制代码
@Component
struct CustomCard {
  // 使用@BuilderParam接收Builder作为参数
  @BuilderParam headerBuilder: () => void
  @BuilderParam contentBuilder: () => void

  build() {
    Column() {
      // 使用传入的headerBuilder
      this.headerBuilder()

      Divider()
        .margin(10)

      // 使用传入的contentBuilder
      this.contentBuilder()
    }
    .padding(15)
    .border({ width: 1, color: Color.Gray })
    .borderRadius(8)
    .width('90%')
    .margin(10)
  }
}

@Entry
@Component
struct BuilderParamExample {
  @Builder
  customHeader() {
    Row() {
      Image($r('app.media.icon'))
        .width(30)
        .height(30)
        .margin({ right: 10 })

      Text('自定义标题')
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
    }
  }

  @Builder
  customContent() {
    Text('这是自定义的内容区域,可以包含任何UI组件和布局')
      .fontSize(14)
      .fontColor(Color.Gray)
  }

  @Builder
  anotherHeader() {
    Text('另一个标题样式')
      .fontSize(20)
      .fontColor(Color.Blue)
      .fontWeight(FontWeight.Bold)
  }

  @Builder
  anotherContent() {
    Column() {
      Text('多行内容')
      Text('第二行内容')
      Button('按钮')
        .margin({ top: 10 })
    }
  }

  build() {
    Column() {
      Text('@BuilderParam示例')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 20 })

      // 使用CustomCard组件,传入不同的Builder
      CustomCard({
        headerBuilder: this.customHeader,
        contentBuilder: this.customContent
      })

      CustomCard({
        headerBuilder: this.anotherHeader,
        contentBuilder: this.anotherContent
      })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .backgroundColor('#F5F5F5')
    .justifyContent(FlexAlign.Start)
  }
}

■ @Builder 与状态管理

c 复制代码
@Entry
@Component
struct AdvancedBuilderExample {
  @State items: string[] = ['苹果', '香蕉', '橙子', '葡萄']
  @State isEditing: boolean = false

  // 动态生成列表项的Builder
  @Builder
  itemListBuilder() {
    Column() {
      ForEach(this.items, (item: string, index: number) => {
        this.listItemBuilder(item, index)
      })
    }
  }

  // 单个列表项的Builder
  @Builder
  listItemBuilder(item: string, index: number) {
    Row() {
      Text(item)
        .fontSize(18)
        .layoutWeight(1)

      if (this.isEditing) {
        Button('删除')
          .onClick(() => {
            this.items.splice(index, 1)
            this.items = [...this.items] // 触发状态更新
          })
          .backgroundColor(Color.Red)
          .fontColor(Color.White)
      }
    }
    .padding(10)
    .border({ width: 1, color: Color.Gray })
    .borderRadius(4)
    .margin({ bottom: 5 })
    .width('100%')
  }

  build() {
    Column({ space: 20 }) {
      Text('高级Builder示例')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)

      this.itemListBuilder()

      Row({ space: 10 }) {
        Button(this.isEditing ? '完成编辑' : '编辑列表')
          .onClick(() => {
            this.isEditing = !this.isEditing
          })

        Button('添加项目')
          .onClick(() => {
            const newItem = `项目${this.items.length + 1}`
            this.items = [...this.items, newItem]
          })
      }
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Start)
  }
}

■ 传递参数

■ 1. 按值传递参数

状态变量的改变不会引起@Builder方法内的UI刷新

typescript 复制代码
@Builder 
function overBuilder(paramA1: string) {
  Row() {
    Text(`UseStateVarByValue: ${paramA1} `)
  }
}
@Entry
@Component
struct Parent {
  @State ppppp: string = 'Hello';
  build() {
    Column() {
      overBuilder(this.ppppp)
    }
  }
}

■ 2. 按引用传递参数

按引用传递参数时,传递的参数可为状态变量,且状态变量的改变会引起@Builder方法内的UI刷新。

c 复制代码
class Tmp {
  paramA1: string = '';
}

@Builder 
function overBuilder(params: Tmp) {
  Row() {
    Text(`UseStateVarByReference: ${params.paramA1} `)
  }
}
@Entry
@Component
struct Parent {
  @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';
      })
    }
  }
}

■ @State状态装饰器

@State装饰的变量,或称为状态变量,一旦变量拥有了状态属性,就和自定义组件的渲染绑定起来。

当状态改变时,UI会发生对应的渲染改变。

■ 示例 -状态改变时 UI会发生对应的渲染改变

c 复制代码
@Entry
@Component
struct CounterExample {
  // 使用@State装饰器声明一个状态变量count,初始值为0
  // 当count的值发生变化时,会触发UI重新渲染
  @State count: number = 0

  // 构建函数,定义UI布局
  build() {
    // 垂直布局容器,设置对齐方式和间距
    Column({ space: 20 }) {
      // 显示计数器当前值
      Text(`当前计数: ${this.count}`)
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.Blue)

      // 增加计数按钮
      Button('增加 +1')
        .onClick(() => {
          // 点击按钮时,count值增加1
          // 由于count是@State变量,UI会自动更新
          this.count++
        })
        .width(200)
        .height(50)
        .backgroundColor(Color.Green)

      // 减少计数按钮
      Button('减少 -1')
        .onClick(() => {
          // 点击按钮时,count值减少1
          this.count--
        })
        .width(200)
        .height(50)
        .backgroundColor(Color.Orange)

      // 重置计数器按钮
      Button('重置')
        .onClick(() => {
          // 点击按钮时,将count重置为0
          this.count = 0
        })
        .width(200)
        .height(50)
        .backgroundColor(Color.Red)
    }
    // 设置Column容器的宽度、高度和对齐方式
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

■ @Prop装饰器:父子单向同步

  • 单向数据流:数据从父组件流向子组件,子组件不能直接修改父组件的数据
  • 同步更新:当父组件的数据变化时,子组件的 @Prop 变量会自动更新
  • 局部修改:子组件可以修改 @Prop 变量的值,但不会影响父组件
  • 类型一致性:@Prop 变量的类型必须与父组件传递的数据类型一致

■ 示例功能说明:

javascript 复制代码
import { ToolBar } from '@ohos.arkui.advanced.ToolBar';

@Entry
@Component
struct ParentComponent {
  // 父组件的状态变量
  @State parentCount: number = 0
  @State parentMessage: string = "Hello from Parent"

  build() {
    Column({ space: 20 }) {
      // 显示父组件的状态
      Text("父组件状态")
        .fontSize(20)
        .fontWeight(FontWeight.Bold)

      Text(`计数: ${this.parentCount}`)
        .fontSize(18)

      Text(`消息: ${this.parentMessage}`)
        .fontSize(18)

      // 修改父组件状态的按钮
      Button('父组件计数+1')
        .onClick(() => {
          this.parentCount++
        })
        .width(200)

      Button('修改父组件消息')
        .onClick(() => {
          this.parentMessage = "父组件消息已更新 " + new Date().toLocaleTimeString()
        })
        .width(200)

      Divider().margin(20)

      // 使用子组件,并通过构造函数传递@Prop数据
      ChildComponent({
        count: this.parentCount,
        message: this.parentMessage
      })
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .justifyContent(FlexAlign.Center)
  }
}

@Component
struct ChildComponent {
  // 使用@Prop装饰器接收父组件传递的数据
  // 当父组件的parentCount变化时,会自动更新这里的count
  @Prop count: number
  // 当父组件的parentMessage变化时,会自动更新这里的message
  @Prop message: string

  // 子组件本地的状态变量
  @State localCount: number = 0

  build() {
    Column({ space: 15 }) {
      Text("子组件状态")
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.Blue)

      Text(`从父组件接收的计数: ${this.count}`)
        .fontSize(16)

      Text(`从父组件接收的消息: ${this.message}`)
        .fontSize(16)
        // .fontColor(Color.Green)

      Text(`子组件本地计数: ${this.localCount}`)
        .fontSize(16)
        // .fontColor(Color.Purple)

      Divider().margin(10)

      // 修改子组件本地状态的按钮
      Button('子组件本地计数+1')
        .onClick(() => {
          this.localCount++
        })
        .width(200)

      // 尝试修改@Prop变量(不会影响父组件)
      Button('尝试修改@Prop计数')
        .onClick(() => {
          // 这个修改只会影响子组件内部,不会同步回父组件
          this.count += 10
          console.log("子组件修改了@Prop count,但不会影响父组件")
        })
        .width(200)
    }
    .padding(15)
    .border({ width: 1, color: Color.Gray })
    .borderRadius(10)
    .margin({ top: 20 })
  }
}

■ @Track装饰器:// 使用@Track装饰器标记需要跟踪的字段

  • 精确跟踪:只跟踪被 @Track 装饰的字段,其他字段的变化不会触发UI更新
  • 性能优化:避免不必要的渲染,提高应用性能
  • 必须与 @Observed 配合使用:@Track 只能用于被 @Observed 装饰的类中的字段
  • 深度观察:对于嵌套对象,需要每一层都使用 @Observed 和 @Track

■ @Observed //定义一个被观察的类,

c 复制代码
// 定义一个被观察的类,使用@Observed装饰器
@Observed
class UserInfo {
  // 使用@Track装饰器标记需要跟踪的字段
  @Track name: string
  @Track age: number
  // 这个字段没有使用@Track,变化不会触发UI更新
  internalId: number = 0

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}
  • 双向数据绑定:父子组件共享同一数据源,任何一方的修改都会同步到另一方.
  • 必须使用符号:在父组件中传递 @Link 变量时,必须使用 variableName 语法.
  • 类型一致性:@Link 变量的类型必须与父组件中的状态变量类型一致.
  • 无需初始化:@Link 变量不能在子组件中初始化,必须从父组件传递.

// 使用@ObjectLink装饰器接收对象,与父组件共享同一对象引用

■ @Watch

@Watch用于监听状态变量的变化,当状态变量变化时,@Watch的回调方法将被调用.

c 复制代码
@Entry
@Component
struct AdvancedWatchExample {
  @State @Watch('onMultipleChange') value1: number = 0
  @State @Watch('onMultipleChange') value2: number = 0
  @State message: string = ""

  // 监听多个状态变化的回调函数
  onMultipleChange() {
    this.message = `值1: ${this.value1}, 值2: ${this.value2}, 总和: ${this.value1 + this.value2}`
  }

  build() {
    Column({ space: 10 }) {
      Text(this.message)
        .fontSize(16)

      Button('增加值1')
        .onClick(() => {
          this.value1 += 1
        })

      Button('增加值2')
        .onClick(() => {
          this.value2 += 1
        })
    }
  }
}

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

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

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

■ @Reusable装饰器:组件复用

■ @Watch装饰器:状态变量更改通知

■ @Styles装饰器:定义组件重用样式

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

■ @Monitor装饰器:状态变量修改监听

■ @Param:组件外部输入

■ @Once:初始化同步一次

■ @Event装饰器:规范组件输出

■ @Provider装饰器和 @Consumer装饰器:跨组件层级双向同步

■ @Type装饰器:标记类属性的类型

相关推荐
花先锋队长3 小时前
从社交破冰到学习规划,鸿蒙5开启智慧校园新生活
华为·生活·harmonyos
用户7227868123448 小时前
HarmonyOS实现快递APP自动识别地址
harmonyos
爱笑的眼睛119 小时前
HarmonyOS声明式UI开发:深入探索ArkUI与Stage模型
华为·harmonyos
爱笑的眼睛119 小时前
HarmonyOS应用开发:深入理解声明式UI与弹窗交互的最佳实践
华为·harmonyos
Cobboo9 小时前
HarmonyOS 5.1.1版本图片上传功能
华为·harmonyos
爱笑的眼睛1118 小时前
HarmonyOS 应用开发新范式:深入探索 Stage 模型与 ArkUI 声明式开发
华为·harmonyos
祥睿夫子1 天前
零基础搞定 ArkTS 类与对象!保姆级教程:定义→创建→测试全流程 + 代码示例
harmonyos
程序员潘Sir1 天前
HarmonyOS实现快递APP自动识别地址
harmonyos·鸿蒙