鸿蒙修饰符

[复制链接]
发表于 2025-12-17 15:16:30 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一、弁言

在HarmonyOS(鸿蒙)应用开辟中,修饰符(Decorator)是一个极其紧张的概念。它们不光可以或许简化开辟过程,还能提供强盛的功能扩展性。本文将深入探究鸿蒙中的各类修饰符,资助开辟者更好地明白和使用这些工具。本文紧张先容@Styles,@Extend,@Builder,@Component,@BuilderParam,@State,@Prop,@Link,@Provide,@Watch,@Observed等等。
   1.1 什么是修饰符

修饰符是一种特殊的语法元素,用@符号作为标识,可以用来修饰类、方法、属性等代码元素,为其添加额外的举动或特性。在鸿蒙开辟中,修饰符紧张用于以下几个方面:


  • UI样式界说和复用
  • 组件声明和管理
  • 状态管理和数据同步
  • 组件间通讯
1.2 修饰符在鸿蒙开辟中的紧张性


1.3 修饰符的作用机制

修饰符在编译时会被转换为特定的代码,它们紧张通过以下机制发挥作用:

  • 装饰器模式: 在不改变原有代码结构的环境下,动态地给对象添加新的功能
  • 编译时转换: 将声明式的代码转换为下令式代码
  • 运行时注入: 在运行时为目的对象注入额外的举动
二、UI装饰类修饰符

   2.1 @Styles修饰符

2.1.1 根本概念和使用场景

@Styles修饰符用于界说可复用的样式聚集,类似于Web开辟中的CSS类。它可以:


  • 提取共同样式,实现复用
  • 保持代码整洁
  • 同一管理样式
2.1.2 使用示例

  1. // 定义全局样式
  2. @Styles function globalStyles() {
  3.   .width('100%')
  4.   .height(100)
  5.   .backgroundColor('#f5f5f5')
  6.   .padding(20)
  7. }
  8. // 使用样式
  9. @Entry
  10. @Component
  11. struct StylesDemo {
  12.   build() {
  13.     Column() {
  14.       Text('Hello')
  15.         .fontSize(20)
  16.         .globalStyles()
  17.       
  18.       Text('World')
  19.         .fontSize(16)
  20.         .globalStyles()
  21.     }
  22.   }
  23. }
复制代码
2.1.3 最佳实践

样式分类管理
  1. // 按功能分类样式
  2. @Styles function cardStyles() {
  3.   .width('100%')
  4.   .padding(15)
  5.   .borderRadius(8)
  6.   .backgroundColor(Color.White)
  7. }
  8. @Styles function buttonStyles() {
  9.   .width(120)
  10.   .height(40)
  11.   .borderRadius(20)
  12.   .backgroundColor('#007DFF')
  13. }
复制代码
2.2 @Extend修饰符

2.2.1 根本概念

@Extend用于扩显现有组件的样式和举动,创建具有特定样式的新组件范例。
2.2.2 使用示例

  1. // 扩展Text组件
  2. @Extend(Text) function primaryText() {
  3.     .fontSize(16)
  4.     .fontColor('#333333')
  5.     .fontWeight(FontWeight.Medium)
  6. }
  7. // 扩展Button组件
  8. @Extend(Button) function primaryButton(color:Color) {
  9.     .width(200)
  10.    .height(50)
  11.    .backgroundColor('#007DFF')
  12.    .fontColor(color)
  13. }
  14. @Entry
  15. @Component
  16. struct TestCase {
  17.    build() {
  18.       Column({ space: 20 }) {
  19.          Text('这是普通文本')
  20.            .primaryText()
  21.          Button('点击按钮')
  22.           .primaryButton(Color.White)
  23.       }
  24.    .height('100%')
  25.    .width('100%')
  26.    }
  27. }
复制代码
2.2.3 @Extend vs @Styles 对比

特性@Extend@Styles使用对象特定组件恣意组件复用性只能用于指定的组件范例可以应用于任何组件范例安全更强的范例查抄相对宽松实用场景组件定制化通用样式复用是否能吸收参数是否2.2.4 使用发起


  • 选择符合的场景

    • 必要创建特定样式的组件变体时,使用@Extend
    • 必要跨组件复用样式时,使用@Styles

  • 定名规范
  1. // 好的命名示例
  2. @Extend(Text) function primaryText() {}
  3. @Extend(Text) function warningText() {}
  4. @Extend(Button) function roundButton() {}
  5. // 避免的命名方式
  6. @Extend(Text) function txt() {}
  7. @Extend(Button) function btn() {}
复制代码
三、组件类修饰符

3.1 @Component修饰符

3.1.1 根本概念

@Component是鸿蒙开辟中最焦点的修饰符之一,用于声明自界说组件。它将一个struct转换为可重用的UI组件,具有以下特点:


  • 必须包罗build()方法
  • 支持组件生命周期
  • 可以包罗状态变量
  • 支持组件间通讯
   3.1.2 @Component vs 平凡函数对比

特性@Component平凡函数状态管理支持@State等状态修饰符不支持状态管理生命周期有完备生命周期没有生命周期重渲染机制相应式更新需手动处置惩罚更新使用场景复杂UI组件简单功能封装3.1.3 根本使用示例

  1. import { promptAction } from '@kit.ArkUI';
  2. @Entry
  3. @Component
  4. struct TestCase {
  5.    // 组件私有状态
  6. @State counter: number = 0
  7.    // 生命周期函数
  8.    aboutToAppear() {
  9.       promptAction.showToast({message:'Component is about to appear'})
  10.    }
  11.    aboutToDisappear() {
  12.       promptAction.showToast({message:'Component is about to disappear'})
  13.    }
  14.    build() {
  15.       Column() {
  16.          Text(`计数器: ${this.counter}`)
  17.            .fontSize(20)
  18.            .fontWeight(FontWeight.Bold)
  19.          Button('增加')
  20.            .onClick(() => {
  21.               this.counter++
  22.            })
  23.            .margin(10)
  24.       }
  25.    .width('100%')
  26.    .padding(20)
  27.    }
  28. }
复制代码
3.1.4 高级特性

1. 组件参数转达
  1. @Component
  2. struct AdvancedComponent {
  3.   // 从父组件接收的属性
  4.   @Prop title: string
  5.   @State private description: string = ''
  6.   build() {
  7.     Column({ space: 10 }) {
  8.       Text(this.title)
  9.         .fontSize(24)
  10.       
  11.       TextInput({ placeholder: '请输入描述' })
  12.         .onChange((value: string) => {
  13.           this.description = value
  14.         })
  15.     }
  16.   }
  17. }
复制代码
2. 组件插槽(Slot)
  1. @Component
  2. struct SlotComponent {
  3.   @BuilderParam content: () => void
  4.   build() {
  5.     Column() {
  6.       this.content()
  7.     }
  8.     .width('100%')
  9.     .backgroundColor('#f5f5f5')
  10.   }
  11. }
  12. // 使用组件插槽
  13. @Component
  14. struct ParentComponent {
  15.   build() {
  16.     SlotComponent() {
  17.       Row() {
  18.         Text('自定义内容')
  19.         Image('icon.png')
  20.       }
  21.     }
  22.   }
  23. }
复制代码
3.1.5 最佳实践


  • 组件拆分原则
  1. // 好的实践:功能单一,职责明确
  2. @Component
  3. struct UserAvatar {
  4.   @Prop userName: string
  5.   @Prop avatarUrl: string
  6.   build() {
  7.     Stack() {
  8.       Image(this.avatarUrl)
  9.         .width(50)
  10.         .height(50)
  11.         .borderRadius(25)
  12.       
  13.       Text(this.userName[0])
  14.         .fontSize(20)
  15.         .fontColor(Color.White)
  16.     }
  17.   }
  18. }
  19. // 使用组件
  20. @Component
  21. struct UserProfile {
  22.   build() {
  23.     Row() {
  24.       UserAvatar({
  25.         userName: "张三",
  26.         avatarUrl: "avatar.png"
  27.       })
  28.       Text("其他信息")
  29.     }
  30.   }
  31. }
复制代码

  • 生命周期使用发起
  1. @Component
  2. struct LifecycleComponent {
  3.   @State private data: any = {}
  4.   aboutToAppear() {
  5.     // 初始化数据,订阅事件
  6.     this.initData()
  7.   }
  8.   aboutToDisappear() {
  9.     // 清理资源,取消订阅
  10.     this.cleanUp()
  11.   }
  12.   private initData() {
  13.     // 数据初始化逻辑
  14.   }
  15.   private cleanUp() {
  16.     // 清理逻辑
  17.   }
  18.   build() {
  19.     // UI渲染
  20.   }
  21. }
复制代码
3.1.6 性能优化发起


  • 状态管理优化
  1. @Component
  2. struct OptimizedComponent {
  3.   // 使用私有变量存储不需要响应式更新的数据
  4.   private staticData: string = 'static'
  5.   
  6.   // 只将需要触发更新的数据声明为@State
  7.   @State dynamicData: number = 0
  8.   build() {
  9.     Column() {
  10.       // 静态内容
  11.       Text(this.staticData)
  12.       
  13.       // 动态内容
  14.       Text(`${this.dynamicData}`)
  15.     }
  16.   }
  17. }
复制代码

  • 条件渲染优化
  1. @Component
  2. struct ConditionalComponent {
  3.   @State loading: boolean = true
  4.   @State data: Array<string> = []
  5.   build() {
  6.     Column() {
  7.       if (this.loading) {
  8.         LoadingSpinner()
  9.       } else {
  10.         ForEach(this.data, (item) => {
  11.           DataItem({ content: item })
  12.         })
  13.       }
  14.     }
  15.   }
  16. }
复制代码
3.2 @BuilderParam修饰符

3.2.1 根本概念

@BuilderParam用于声明自界说构建函数参数,使组件可以或许吸收和渲染自界说内容。
3.2.2 使用场景


  • 自界说列表项渲染
  1. @Component
  2. struct MainPage {
  3. @State items: string[] = ['项目1', '项目2', '项目3']
  4. @Builder myItemBuilder(item: string):void{}
  5. @BuilderParam itemBuilder: (item: string) => void =  this.myItemBuilder
  6.    build() {
  7.       List() {
  8.          ForEach(this.items, (item:string,idx:number) => {
  9.             ListItem() {
  10.                this.itemBuilder(item)
  11.             }
  12.          })
  13.       }
  14.    }
  15. }
  16. // 使用示例
  17. @Entry
  18. @Component
  19. struct TestCase {
  20.    build() {
  21.       Column(){
  22.          MainPage({
  23.             itemBuilder: (item:string) => {
  24.                Row() {
  25.                   Text(item).width('100%')
  26.                     .height('100%')
  27.                     .backgroundColor(Color.Pink)
  28.                }
  29.             }
  30.          })
  31.       }}
  32. }
复制代码
  1. @Component
  2. struct Container {
  3.   @BuilderParam header?: () => void
  4.   @BuilderParam content: () => void
  5.   @BuilderParam footer?: () => void
  6.   build() {
  7.     Column() {
  8.       if (this.header) {
  9.         this.header()
  10.       }
  11.       
  12.       this.content()
  13.       
  14.       if (this.footer) {
  15.         this.footer()
  16.       }
  17.     }
  18.   }
  19. }
复制代码
3.2.3 注意事项与最佳实践


  • 参数定名规范
  1. // 推荐的命名方式
  2. @BuilderParam headerBuilder: () => void
  3. @BuilderParam contentBuilder: () => void
  4. @BuilderParam footerBuilder: () => void
  5. // 不推荐的命名方式
  6. @BuilderParam hdr: () => void
  7. @BuilderParam cnt: () => void
复制代码
  1. @Component
  2. struct PerformanceOptimizedList {
  3.    // 使用私有变量缓存不常变化的构建函数
  4. @Builder myStaticBuilder() :void{
  5.       Text('Static Content')
  6. }
  7. @BuilderParam private staticBuilder:()=>void = this.myStaticBuilder
  8. @BuilderParam dynamicBuilder: () => void
  9.   build() {
  10.       Column() {
  11.          // 静态内容
  12.          this.staticBuilder()
  13.          // 动态内容
  14.          this.dynamicBuilder()
  15.       }
  16.    }
  17. }
复制代码
四、状态管理类修饰符

4.1 @State修饰符

4.1.1 根本概念

@State是鸿蒙应用中最根本的状态管理修饰符,用于组件内部状态管理。当@State装饰的变量发生变革时,框架会主动重新渲染相干UI。
   4.1.2 使用规则


  • 根本语法
  1. interface IUser{
  2.    name: string,
  3.    age: number
  4. }
  5. // 使用示例
  6. @Entry
  7. @Component
  8. struct TestCase {
  9.    // 基础类型
  10.    @State count: number = 0
  11.    // 对象类型
  12.    @State user: IUser  = {
  13.       name: 'tata',
  14.       age: 25
  15.    }
  16.       // 数组类型
  17.    @State list: string[] = ['item1', 'item2']
  18.    build() {
  19.       Column({ space: 20 }) {
  20.          // 使用状态变量
  21.          Text(`Count: ${this.count}`)
  22.          Button('Add')
  23.            .onClick(() => {
  24.               this.count++
  25.            })
  26.          Text(`User: ${this.user.name}, ${this.user.age}`)
  27.          Button('Update User')
  28.            .onClick(() => {
  29.               // 对象更新要使用新对象
  30.               this.user = {
  31.                  name:this.user.name,
  32.                  age: this.user.age + 1
  33.               }
  34.            })
  35.       }
  36.    }
  37. }
复制代码
4.1.3 @State注意事项和最佳实践


  • 状态初始化
  1. @Component
  2. struct StateInitDemo {
  3.   // ✅ 推荐:直接初始化
  4.   @State counter1: number = 0
  5.   
  6.   // ⚠️ 不推荐:延迟初始化可能导致问题
  7.   @State counter2: number
  8.   aboutToAppear() {
  9.     // 延迟初始化可能导致首次渲染问题
  10.     this.counter2 = 0
  11.   }
  12. }
复制代码

  • 状态粒度控制
  1. @Component
  2. struct StateGranularityDemo {
  3.   // ❌ 错误:粒度过大
  4.   @State entirePage: {
  5.     header: object,
  6.     content: object,
  7.     footer: object
  8.   }
  9.   // ✅ 正确:适当的状态粒度
  10.   @State headerConfig: object
  11.   @State contentList: array
  12.   @State footerVisible: boolean
  13.   build() {
  14.     Column() {
  15.       // UI实现
  16.     }
  17.   }
  18. }
复制代码
4.2 @Prop修饰符

4.2.1 根本概念

@Prop用于父子组件间的单向数据转达,子组件通过@Prop吸收父组件转达的数据。
4.2.2 使用示例

  1. // 子组件
  2. @Component
  3. struct ChildComponent {
  4.   @Prop count: number  // 接收父组件传递的数值
  5.   @Prop message: string  // 接收父组件传递的字符串
  6.   build() {
  7.     Column() {
  8.       Text(`Count: ${this.count}`)
  9.       Text(`Message: ${this.message}`)
  10.     }
  11.   }
  12. }
  13. // 父组件
  14. @Component
  15. struct ParentComponent {
  16.   @State parentCount: number = 0
  17.   @State parentMessage: string = 'Hello'
  18.   build() {
  19.     Column() {
  20.       // 传递属性给子组件
  21.       ChildComponent({
  22.         count: this.parentCount,
  23.         message: this.parentMessage
  24.       })
  25.       Button('Update Parent')
  26.         .onClick(() => {
  27.           this.parentCount++
  28.           this.parentMessage = 'Updated'
  29.         })
  30.     }
  31.   }
  32. }
复制代码
4.2.3 @Prop vs 平凡变量对比

  1. @Component
  2. struct PropComparisonDemo {
  3.   // @Prop装饰的变量
  4.   @Prop propValue: number
  5.   
  6.   // 普通变量
  7.   normalValue: number
  8.   build() {
  9.     Column() {
  10.       // @Prop变量会响应父组件的更新
  11.       Text(`Prop Value: ${this.propValue}`)
  12.       
  13.       // 普通变量不会响应更新
  14.       Text(`Normal Value: ${this.normalValue}`)
  15.     }
  16.   }
  17. }
复制代码
特性@Prop变量平凡变量数据流向单向(父到子)无数据流相应更新主动相应不相应可修改性当地可修改但不影响父组件可以自由修改使用场景父子组件通讯组件内部数据4.2.4 @Prop的高级用法


  • 默认值处置惩罚
  1. @Component
  2. struct PropDefaultDemo {
  3.   // 使用装饰器提供默认值
  4.   @Prop defaultValue: number = 100
  5.   build() {
  6.     Column() {
  7.       Text(`Value: ${this.defaultValue}`)
  8.     }
  9.   }
  10. }
复制代码

  • 属性监听与处置惩罚
  1. @Component
  2. struct PropWatchDemo {
  3.   @Prop @Watch('onCountChange') count: number
  4.   @State localCount: number = 0
  5.   onCountChange() {
  6.     // 当@Prop值变化时执行
  7.     this.localCount = this.count * 2
  8.   }
  9.   build() {
  10.     Column() {
  11.       Text(`Prop Count: ${this.count}`)
  12.       Text(`Local Count: ${this.localCount}`)
  13.     }
  14.   }
  15. }
复制代码
4.2.5 最佳实践


  • 属性定名规范
  1. @Component
  2. struct PropNamingDemo {
  3.   // ✅ 推荐:语义化命名
  4.   @Prop isVisible: boolean
  5.   @Prop userName: string
  6.   @Prop itemCount: number
  7.   // ❌ 避免:模糊的命名
  8.   @Prop flag: boolean
  9.   @Prop str: string
  10.   @Prop num: number
  11. }
复制代码
  1. @Component
  2. struct PropTypeDemo {
  3.   // ✅ 推荐:明确的类型定义
  4.   @Prop items: Array<{
  5.     id: number,
  6.     name: string
  7.   }>
  8.   // ❌ 避免:使用any类型
  9.   @Prop data: any
  10. }
复制代码
4.3 @Link修饰符

4.3.1 根本概念

@Link修饰符用于实现父子组件间的双向数据绑定。与@Prop差别,@Link装饰的变量在子组件中的修改会同步回父组件。
   4.3.2 使用示例

  1. // 子组件
  2. @Component
  3. struct LinkChildComponent {
  4.   @Link countValue: number  // 双向绑定数据
  5.   build() {
  6.     Column() {
  7.       Text(`Count: ${this.countValue}`)
  8.       Button('在子组件中修改')
  9.         .onClick(() => {
  10.           this.countValue++  // 修改会影响父组件
  11.         })
  12.     }
  13.   }
  14. }
  15. // 父组件
  16. @Entry
  17. @Component
  18. struct TestCase {
  19.   @State parentCount: number = 0
  20.   build() {
  21.     Column() {
  22.       Text(`Parent Count: ${this.parentCount}`)
  23.       LinkChildComponent({ countValue: $parentCount })
  24.       Button('在父组件中修改')
  25.         .onClick(() => {
  26.           this.parentCount++
  27.         })
  28.     }
  29.   }
  30. }
复制代码
4.3.3 @Link vs @Prop 对比

特性@Link@Prop数据流向双向单向(父到子)子组件修改直接影响父组件不影响父组件使用场景必要子组件修改父组件状态只必要展示父组件数据语法标志变量名变量名4.3.4 @Link最佳实践


  • 公道使用场景
  1. @Component
  2. struct FormComponent {
  3.   // ✅ 适合使用@Link的场景:表单数据
  4.   @Link formData: {
  5.     username: string,
  6.     password: string
  7.   }
  8.   build() {
  9.     Column() {
  10.       TextInput({ placeholder: '用户名' })
  11.         .onChange((value) => {
  12.           this.formData.username = value
  13.         })
  14.       
  15.       TextInput({ placeholder: '密码' })
  16.         .type(InputType.Password)
  17.         .onChange((value) => {
  18.           this.formData.password = value
  19.         })
  20.     }
  21.   }
  22. }
复制代码

  • 制止过分使用
  1. @Component
  2. struct OptimizedComponent {
  3.   // ✅ 只对需要双向绑定的数据使用@Link
  4.   @Link editableData: string
  5.   
  6.   // ✅ 只读数据使用@Prop
  7.   @Prop readOnlyData: string
  8.   
  9.   // ✅ 组件内部状态使用@State
  10.   @State localState: number = 0
  11.   build() {
  12.     Column() {
  13.       // 实现UI
  14.     }
  15.   }
  16. }
复制代码
4.4 @Provide/@Consume修饰符

4.4.1 根本概念

@Provide和@Consume用于实现跨组件层级的数据共享,制止多层props转达(即"prop drilling"标题)。
4.4.2 根本用法

  1. interface IUser{
  2.   name:string,
  3.   role:string
  4. }
  5. // 顶层组件
  6. @Entry
  7. @Component
  8. struct TestCase {
  9.   @Provide('theme') theme: string = 'light'
  10.   @Provide('user') userInfo:IUser  = {
  11.     name: 'tata',
  12.     role: 'admin'
  13.   }
  14.   build() {
  15.     Column() {
  16.       ConsumerComponent()
  17.     }
  18.   }
  19. }
  20. // 消费组件(可以是任意层级的子组件)
  21. @Component
  22. struct ConsumerComponent {
  23.   @Consume('theme') theme: string
  24.   @Consume('user') userInfo: IUser
  25.   build() {
  26.     Column() {
  27.       Text(`Current Theme: ${this.theme}`)
  28.       Text(`User: ${this.userInfo.name}`)
  29.     }
  30.   }
  31. }
复制代码
4.4.3 高级特性


  • 使用别名
  1. @Component
  2. struct AdvancedProvider {
  3.   @Provide('systemTheme') theme: string = 'light'
  4. }
  5. @Component
  6. struct AdvancedConsumer {
  7.   // 使用别名访问共享数据
  8.   @Consume('systemTheme') currentTheme: string
  9.   build() {
  10.     Column() {
  11.       Text(`Theme: ${this.currentTheme}`)
  12.     }
  13.   }
  14. }
复制代码

  • 多层级数据共享
  1. @Component
  2. struct AppRoot {
  3.   @Provide('globalState') userInfo:IUser = {
  4.     name:'tata',
  5.     role:'admin'
  6.   }
  7.   build() {
  8.     Column() {
  9.       // 可以被任意深度的子组件访问
  10.       DeepNestedComponent()
  11.     }
  12.   }
  13. }
复制代码
4.4.4 使用发起与最佳实践


  • 公道的数据粒度
  1. // ✅ 推荐:适当的粒度
  2. @Component
  3. struct GoodProvider {
  4.   @Provide('userSettings') settings: UserSettings
  5.   @Provide('appTheme') theme: Theme
  6. }
  7. // ❌ 避免:过大的共享范围
  8. @Component
  9. struct BadProvider {
  10.   @Provide('entireAppState') state: AppState
  11. }
复制代码
  1. @Component
  2. struct OptimizedProvider {
  3.   // 将频繁变化的数据和稳定数据分开
  4.   @Provide('staticConfig') staticConfig: Config // 稳定数据
  5.   @Provide('dynamicState') dynamicState: State // 变化数据
  6.   build() {
  7.     Column() {
  8.       // 实现UI
  9.     }
  10.   }
  11. }
复制代码

  • 错误处置惩罚
  1. @Component
  2. struct SafeConsumer {
  3.   @Consume('data') data?: DataType  // 使用可选类型
  4.   
  5.   build() {
  6.     Column() {
  7.       if (this.data) {
  8.         // 安全地使用数据
  9.         Text(this.data.toString())
  10.       } else {
  11.         // 提供后备UI
  12.         Text('数据未就绪')
  13.       }
  14.     }
  15.   }
  16. }
复制代码
4.5 @Watch修饰符

4.5.1 根本概念

@Watch用于监听状态变量的变革,当被监听的状态发生改变时,会触发相应的回调函数。
   4.5.2 根本用法

  1. // 顶层组件
  2. @Entry
  3. @Component
  4. struct TestCase {
  5.   @State @Watch('onCountChange') count: number = 0
  6.   @State message: string = ''
  7.   onCountChange() {
  8.     this.message = `计数变为 ${this.count.toString()}`
  9.   }
  10.   build() {
  11.     Column({ space: 20 }) {
  12.       Text(`Current count: ${this.count}`)
  13.       Text(this.message)
  14.       Button('Increment')
  15.         .onClick(() => {
  16.           this.count++
  17.         })
  18.     }
  19.   }
  20. }
复制代码
4.5.3 高级用法


  • 监听多个属性
  1. @Component
  2. struct MultiWatchDemo {
  3.   @State @Watch('onScoreChange') score: number = 0
  4.   @State @Watch('onScoreChange') bonus: number = 0
  5.   // 监听多个数值变化
  6.   onScoreChange() {
  7.     console.info(`Total: ${this.score + this.bonus}`)
  8.   }
  9.   build() {
  10.     Column() {
  11.       // UI实现
  12.     }
  13.   }
  14. }
复制代码

  • 条件监听
  1. @Component
  2. struct ConditionalWatchDemo {
  3.   @State @Watch('onValueChange') value: number = 0
  4.   @State isEnabled: boolean = true
  5.   onValueChange(newValue: number, oldValue: number) {
  6.     if (this.isEnabled) {
  7.       // 只在启用状态下处理变化
  8.       this.handleValueChange(newValue, oldValue)
  9.     }
  10.   }
  11.   private handleValueChange(newVal: number, oldVal: number) {
  12.     // 处理逻辑
  13.   }
  14.   build() {
  15.     Column() {
  16.       Switch()
  17.         .checked(this.isEnabled)
  18.         .onChange((value: boolean) => {
  19.           this.isEnabled = value
  20.         })
  21.     }
  22.   }
  23. }
复制代码
4.5.4 @Watch使用场景


  • 表单验证
  1. @Component
  2. struct FormValidationDemo {
  3.   @State @Watch('validateEmail') email: string = ''
  4.   @State emailError: string = ''
  5.   validateEmail(newValue: string) {
  6.     const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
  7.     if (!emailRegex.test(newValue)) {
  8.       this.emailError = '请输入有效的邮箱地址'
  9.     } else {
  10.       this.emailError = ''
  11.     }
  12.   }
  13.   build() {
  14.     Column({ space: 10 }) {
  15.       TextInput({ placeholder: '请输入邮箱' })
  16.         .onChange((value: string) => {
  17.           this.email = value
  18.         })
  19.       
  20.       if (this.emailError) {
  21.         Text(this.emailError)
  22.           .fontSize(12)
  23.           .fontColor(Color.Red)
  24.       }
  25.     }
  26.   }
  27. }
复制代码

  • 数据同步
  1. @Component
  2. struct DataSyncDemo {
  3.   @State @Watch('syncToServer') localData: IUser = {}
  4.   async syncToServer(newValue: IUser) {
  5.     try {
  6.       await this.saveToServer(newValue)
  7.       console.info('Data synced successfully')
  8.     } catch (error) {
  9.       console.error('Sync failed:', error)
  10.     }
  11.   }
  12.   private async saveToServer(data: object) {
  13.     // 实现服务器同步逻辑
  14.   }
  15.   build() {
  16.     Column() {
  17.       // UI实现
  18.     }
  19.   }
  20. }
复制代码
4.5.5 最佳实践


  • 性能优化
  1. @Component
  2. struct WatchOptimizationDemo {
  3.   @State @Watch('onDataChange') data: IUser = {
  4.     name:'tata',
  5.     role:'admin'
  6.   }
  7.   // ✅ 优化:添加防抖处理
  8.   private debounceTimer: number = -1
  9.   onDataChange() {
  10.     if (this.debounceTimer !== -1) {
  11.       clearTimeout(this.debounceTimer)
  12.     }
  13.     this.debounceTimer = setTimeout(() => {
  14.       this.processDataChange(this.data)
  15.       this.debounceTimer = -1
  16.     }, 300)
  17.   }
  18.   private processDataChange(data: IUser) {
  19.     // 处理数据变化
  20.   }
  21.   build() {
  22.     Column() {
  23.       // UI实现
  24.     }
  25.   }
  26. }
复制代码

  • 错误处置惩罚
  1. @Component
  2. struct WatchErrorHandlingDemo {
  3.   @State @Watch('onDataChange') data: IUser = {
  4.     name:'tata',
  5.     role:'admin'
  6.   }
  7.   onDataChange() {
  8.     try {
  9.       // 数据验证
  10.       if (!this.isValidData(this.data)) {
  11.         throw new Error('Invalid data format')
  12.       }
  13.       // 处理数据
  14.       this.processData(this.data)
  15.     } catch (error) {
  16.       console.error('Error in watch handler:', error)
  17.       // 恢复到之前的值
  18.       // 显示错误提示
  19.       this.showError(error.message)
  20.     }
  21.   }
  22.   private isValidData(data: IUser): boolean {
  23.     // 实现数据验证逻辑
  24.     return true
  25.   }
  26.   private processData(data: IUser) {
  27.     // 处理数据
  28.   }
  29.   private showError(message: string) {
  30.     // 显示错误提示
  31.   }
  32.   build() {
  33.     Column() {
  34.       // UI实现
  35.     }
  36.   }
  37. }
复制代码
4.5.6 @Watch注意事项


  • 制止无穷循环
  1. @Component
  2. struct WatchCycleDemo {
  3.   @State @Watch('onValueChange') value1: number = 0
  4.   @State @Watch('onValue2Change') value2: number = 0
  5.   // ❌ 错误:可能导致无限循环
  6.   onValueChange() {
  7.     this.value2++ // 触发value2的watch
  8.   }
  9.   onValue2Change() {
  10.     this.value1++ // 触发value1的watch
  11.   }
  12.   // ✅ 正确:添加循环保护
  13.   private updateCount: number = 0
  14.   private readonly MAX_UPDATES: number = 3
  15.   onSafeValueChange() {
  16.     if (this.updateCount < this.MAX_UPDATES) {
  17.       this.updateCount++
  18.       this.value2++
  19.     } else {
  20.       this.updateCount = 0
  21.     }
  22.   }
  23. }
复制代码

  • 同步与异步处置惩罚
  1. @Component
  2. struct WatchAsyncDemo {
  3.   @State @Watch('onDataChange') data: object = {}
  4.   // ✅ 处理异步操作
  5.   async onDataChange(newValue: object) {
  6.     try {
  7.       await this.validateData(newValue)
  8.       await this.saveData(newValue)
  9.     } catch (error) {
  10.       console.error('Async operation failed:', error)
  11.     }
  12.   }
  13.   private async validateData(data: object): Promise<void> {
  14.     // 异步数据验证
  15.   }
  16.   private async saveData(data: object): Promise<void> {
  17.     // 异步保存数据
  18.   }
  19.   build() {
  20.     Column() {
  21.       // UI实现
  22.     }
  23.   }
  24. }
复制代码
  

  • @Watch 回调函数现实上不支持有用的参数转达
  • 回调函数中第一个参数是被监听属性的名称字符串
  4.6 @Observed/@ObjectLink修饰符

4.6.1 根本概念

@Observed和@ObjectLink是用于对象范例数据的相应式管理修饰符:


  • @Observed:将一个类标志为可观察对象
  • @ObjectLink:用于在组件间创建对象的引用关系,实现对象级别的双向同步
   4.6.2 根本用法

  1. // 定义可观察类
  2. @Observed
  3. class Student {
  4.   name: string
  5.   age: number
  6.   scores: number[]
  7.   constructor(name: string, age: number) {
  8.     this.name = name
  9.     this.age = age
  10.     this.scores = []
  11.   }
  12. }
  13. // 父组件
  14. @Component
  15. struct ParentComponent {
  16.   // 创建可观察对象实例
  17.   @State student: Student = new Student('tata', 18)
  18.   build() {
  19.     Column() {
  20.       // 传递给子组件
  21.       StudentCard({ studentInfo: this.student })
  22.       
  23.       Button('修改信息')
  24.         .onClick(() => {
  25.           this.student.age++
  26.           this.student.scores.push(100)
  27.         })
  28.     }
  29.   }
  30. }
  31. // 子组件
  32. @Component
  33. struct StudentCard {
  34.   // 使用ObjectLink引用父组件的对象
  35.   @ObjectLink studentInfo: Student
  36.   build() {
  37.     Column() {
  38.       Text(`姓名: ${this.studentInfo.name}`)
  39.       Text(`年龄: ${this.studentInfo.age}`)
  40.       ForEach(this.studentInfo.scores, (score:number) => {
  41.         Text(`分数: ${score}`)
  42.       })
  43.     }
  44.   }
  45. }
复制代码
4.6.3 关键点


  • 类级别装饰器
  1. // ✅ 正确:整个类使用 @Observed
  2. @Observed
  3. class Model {
  4.   property1: string
  5.   property2: number
  6. }
  7. // ❌ 错误:不能装饰属性
  8. class WrongModel {
  9.   @Observed property: string  // 这是错误的用法
  10. }
复制代码

  • 嵌套对象处置惩罚
  1. @Observed
  2. class Parent {
  3.   child: Child  // 如果 Child 需要观察,Child 类也需要使用 @Observed 装饰器
  4. }
  5. @Observed
  6. class Child {
  7.   name: string
  8. }
复制代码

  • 数组处置惩罚
  1. @Observed
  2. class TodoList {
  3.   items: Array<TodoItem>  // TodoItem 类需要使用 @Observed
  4.   addItem(item: TodoItem) {
  5.     this.items.push(item)
  6.   }
  7. }
  8. @Observed
  9. class TodoItem {
  10.   content: string
  11.   completed: boolean
  12. }
复制代码
4.6.4 现实应用示例

  1. // 定义观察类
  2. @Observed
  3. class Profile {
  4.   name: string
  5.   age: number
  6.   constructor(name: string, age: number) {
  7.     this.name = name
  8.     this.age = age
  9.   }
  10. }
  11. // 父组件
  12. @Component
  13. struct ProfileManager {
  14.   @State profile: Profile = new Profile('tata', 25)
  15.   build() {
  16.     Column() {
  17.       // 传递给子组件
  18.       ProfileEditor({ userProfile: this.profile })
  19.       ProfileDisplay({ userProfile: this.profile })
  20.     }
  21.   }
  22. }
  23. // 编辑组件
  24. @Component
  25. struct ProfileEditor {
  26.   @ObjectLink userProfile: Profile
  27.   build() {
  28.     Column() {
  29.       Button('修改年龄')
  30.         .onClick(() => {
  31.           this.userProfile.age++  // 直接修改将触发更新
  32.         })
  33.     }
  34.   }
  35. }
  36. // 显示组件
  37. @Component
  38. struct ProfileDisplay {
  39.   @ObjectLink userProfile: Profile
  40.   build() {
  41.     Column() {
  42.       Text(`姓名: ${this.userProfile.name}`)
  43.       Text(`年龄: ${this.userProfile.age}`)
  44.     }
  45.   }
  46. }
复制代码
4.6.5 注意事项


  • @Observed 只能用于类声明
  • 不能用于装饰类的属性
  • 嵌套对象如需相应式,必要分别使用 @Observed 装饰器
  • 共同 @ObjectLink 使用来实现组件间的数据同步
  • 观察对象的属性修改会主动触发相干组件的更新
对比

让我详细对比这些修饰符的区别:
   1. 使用场景对比

修饰符使用对象数据流向使用场景@State根本范例/对象/数组组件内部管理组件内部状态@Prop根本范例/对象/数组父 -> 子父组件向子组件转达数据@Link根本范例/对象/数组双向父子组件双向数据同步@Observed/@ObjectLink类实例多组件共享复杂对象的相应式管理2. 详细示例对比

  1. // @State:组件内部状态管理
  2. @Component
  3. struct StateExample {
  4.   @State count: number = 0  // 组件内部状态
  5.   build() {
  6.     Column() {
  7.       Text(`Count: ${this.count}`)
  8.       Button('Add').onClick(() => this.count++)
  9.     }
  10.   }
  11. }
  12. // @Prop:单向数据流
  13. @Component
  14. struct PropExample {
  15.   @Prop title: string  // 从父组件接收数据
  16.   
  17.   build() {
  18.     Text(this.title)
  19.   }
  20. }
  21. // @Link:双向数据绑定
  22. @Component
  23. struct LinkExample {
  24.   @Link message: string  // 与父组件双向绑定
  25.   
  26.   build() {
  27.     TextInput({ text: this.message })
  28.       .onChange((value: string) => {
  29.         this.message = value  // 修改会影响父组件
  30.       })
  31.   }
  32. }
  33. // @Observed:对象响应式
  34. @Observed
  35. class User {
  36.   name: string
  37.   age: number
  38.   constructor(name: string, age: number) {
  39.     this.name = name
  40.     this.age = age
  41.   }
  42. }
  43. @Component
  44. struct ObservedExample {
  45.   @State user: User = new User('tata', 25)
  46.   build() {
  47.     Column() {
  48.       UserCard({ userInfo: this.user })  // 传递给子组件
  49.     }
  50.   }
  51. }
  52. @Component
  53. struct UserCard {
  54.   @ObjectLink userInfo: User  // 引用观察对象
  55.   build() {
  56.     Column() {
  57.       Text(`Name: ${this.userInfo.name}`)
  58.       Button('Age++')
  59.         .onClick(() => {
  60.           this.userInfo.age++  // 直接修改对象属性
  61.         })
  62.     }
  63.   }
  64. }
复制代码
3. 特点对比

@State



  • 用于组件内部状态管理
  • 值变革会触发组件重新渲染
  • 可以管理任何范例的数据
  1. @State count: number = 0
  2. @State user: Object = {}
  3. @State list: string[] = []
复制代码
@Prop



  • 实现单向数据流
  • 子组件不能直接修改父组件数据
  • 父组件数据变革会更新子组件
  1. // 父组件
  2. @State title: string = 'Hello'
  3. // 子组件使用
  4. @Prop title: string
复制代码
@Link



  • 实现双向数据绑定
  • 子组件可以直接修改数据
  • 数据变革双向同步
  1. // 父组件
  2. @State message: string = ''
  3. // 子组件使用
  4. @Link message: string
复制代码
@Observed/@ObjectLink



  • 用于复杂对象的相应式管理
  • 主动跟踪对象属性变革
  • 支持多组件共享和同步
  1. @Observed
  2. class Model {
  3.   // 整个类的属性都会被观察
  4. }
  5. @ObjectLink model: Model  // 引用观察对象
复制代码
4. 数据同步方式对比

  1. // @State:组件内直接修改
  2. @State value: number = 0
  3. this.value = 1  // 直接赋值
  4. // @Prop:不能直接修改
  5. @Prop title: string
  6. this.title = 'new'  // ❌ 错误
  7. // @Link:双向同步
  8. @Link count: number
  9. this.count++  // ✅ 会同步到父组件
  10. // @Observed:对象属性修改
  11. @ObjectLink user: User
  12. this.user.name = 'new name'  // ✅ 自动触发更新
复制代码


回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表