鸿蒙修饰符

文章目录

  • 一、引言
    • 1.1 什么是修饰符
    • 1.2 修饰符在鸿蒙开发中的重要性
    • 1.3 修饰符的作用机制
  • 二、UI装饰类修饰符
    • 2.1 @Styles修饰符
      • 2.1.1 基本概念和使用场景
      • 2.1.2 使用示例
      • 2.1.3 最佳实践
    • 2.2 @Extend修饰符
      • 2.2.1 基本概念
      • 2.2.2 使用示例
      • 2.2.3 @Extend vs @Styles 对比
      • 2.2.4 使用建议
  • 三、组件类修饰符
    • 3.1 @Component修饰符
      • 3.1.1 基本概念
      • 3.1.2 @Component vs 普通函数对比
      • 3.1.3 基础使用示例
      • 3.1.4 高级特性
      • 3.1.5 最佳实践
      • 3.1.6 性能优化建议
    • 3.2 @BuilderParam修饰符
      • 3.2.1 基本概念
      • 3.2.2 使用场景
      • 3.2.3 注意事项与最佳实践
  • 四、状态管理类修饰符
    • 4.1 @State修饰符
      • 4.1.1 基本概念
      • 4.1.2 使用规则
      • 4.1.3 @State注意事项和最佳实践
    • 4.2 @Prop修饰符
      • 4.2.1 基本概念
      • 4.2.2 使用示例
      • 4.2.3 @Prop vs 普通变量对比
      • 4.2.4 @Prop的高级用法
      • 4.2.5 最佳实践
    • 4.3 @Link修饰符
      • 4.3.1 基本概念
      • 4.3.2 使用示例
      • 4.3.3 @Link vs @Prop 对比
      • 4.3.4 @Link最佳实践
    • 4.4 @Provide/@Consume修饰符
      • 4.4.1 基本概念
      • 4.4.2 基础用法
      • 4.4.3 高级特性
      • 4.4.4 使用建议与最佳实践
    • 4.5 @Watch修饰符
      • 4.5.1 基本概念
      • 4.5.2 基础用法
      • 4.5.3 高级用法
      • 4.5.4 @Watch使用场景
      • 4.5.5 最佳实践
      • 4.5.6 @Watch注意事项
    • 4.6 @Observed/@ObjectLink修饰符
      • 4.6.1 基本概念
      • 4.6.2 基础用法
      • 4.6.3 关键点
      • 4.6.4 实际应用示例
      • 4.6.5 注意事项
    • 对比
      • 1. 使用场景对比
      • 2. 具体示例对比
      • 3. 特点对比
        • @State
        • @Prop
        • @Link
        • @Observed/@ObjectLink
      • 4. 数据同步方式对比

一、引言

在HarmonyOS(鸿蒙)应用开发中,修饰符(Decorator)是一个极其重要的概念。它们不仅能够简化开发过程,还能提供强大的功能扩展性。本文将深入探讨鸿蒙中的各类修饰符,帮助开发者更好地理解和使用这些工具。本文主要介绍@Styles@Extend@Builder@Component@BuilderParam@State@Prop@Link@Provide@Watch@Observed等等。

HarmonyOS Decorators
UI Decorators
Component Decorators
State Management
Styles
Extend
Component
BuilderParam
State
Prop
Link

1.1 什么是修饰符

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

  • UI样式定义和复用
  • 组件声明和管理
  • 状态管理和数据同步
  • 组件间通信

1.2 修饰符在鸿蒙开发中的重要性

请添加图片描述

1.3 修饰符的作用机制

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

  1. 装饰器模式: 在不改变原有代码结构的情况下,动态地给对象添加新的功能
  2. 编译时转换: 将声明式的代码转换为命令式代码
  3. 运行时注入: 在运行时为目标对象注入额外的行为

二、UI装饰类修饰符

UI Decorator
Styles
Extend
Global Styles
Theme Styles
Component Extensions
Custom Components

2.1 @Styles修饰符

2.1.1 基本概念和使用场景

@Styles修饰符用于定义可复用的样式集合,类似于Web开发中的CSS类。它可以:

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

2.1.2 使用示例

// 定义全局样式
@Styles function globalStyles() {.width('100%').height(100).backgroundColor('#f5f5f5').padding(20)
}// 使用样式
@Entry
@Component
struct StylesDemo {build() {Column() {Text('Hello').fontSize(20).globalStyles()Text('World').fontSize(16).globalStyles()}}
}

2.1.3 最佳实践

样式分类管理

// 按功能分类样式
@Styles function cardStyles() {.width('100%').padding(15).borderRadius(8).backgroundColor(Color.White)
}@Styles function buttonStyles() {.width(120).height(40).borderRadius(20).backgroundColor('#007DFF')
}

2.2 @Extend修饰符

2.2.1 基本概念

@Extend用于扩展现有组件的样式和行为,创建具有特定样式的新组件类型。

2.2.2 使用示例

// 扩展Text组件
@Extend(Text) function primaryText() {.fontSize(16).fontColor('#333333').fontWeight(FontWeight.Medium)
}// 扩展Button组件
@Extend(Button) function primaryButton(color:Color) {.width(200).height(50).backgroundColor('#007DFF').fontColor(color)
}@Entry
@Component
struct TestCase {build() {Column({ space: 20 }) {Text('这是普通文本').primaryText()Button('点击按钮').primaryButton(Color.White)}.height('100%').width('100%')}
}

2.2.3 @Extend vs @Styles 对比

特性@Extend@Styles
使用对象特定组件任意组件
复用性只能用于指定的组件类型可以应用于任何组件
类型安全更强的类型检查相对宽松
适用场景组件定制化通用样式复用
是否能接收参数

2.2.4 使用建议

  1. 选择合适的场景

    • 需要创建特定样式的组件变体时,使用@Extend
    • 需要跨组件复用样式时,使用@Styles
  2. 命名规范

// 好的命名示例
@Extend(Text) function primaryText() {}
@Extend(Text) function warningText() {}
@Extend(Button) function roundButton() {}// 避免的命名方式
@Extend(Text) function txt() {}
@Extend(Button) function btn() {}

三、组件类修饰符

3.1 @Component修饰符

3.1.1 基本概念

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

  • 必须包含build()方法
  • 支持组件生命周期
  • 可以包含状态变量
  • 支持组件间通信
Component
生命周期管理
状态管理
UI渲染
aboutToAppear
aboutToDisappear
State
Prop
build方法

3.1.2 @Component vs 普通函数对比

特性@Component普通函数
状态管理支持@State等状态修饰符不支持状态管理
生命周期有完整生命周期没有生命周期
重渲染机制响应式更新需手动处理更新
使用场景复杂UI组件简单功能封装

3.1.3 基础使用示例

import { promptAction } from '@kit.ArkUI';@Entry
@Component
struct TestCase {// 组件私有状态
@State counter: number = 0// 生命周期函数aboutToAppear() {promptAction.showToast({message:'Component is about to appear'})}aboutToDisappear() {promptAction.showToast({message:'Component is about to disappear'})}build() {Column() {Text(`计数器: ${this.counter}`).fontSize(20).fontWeight(FontWeight.Bold)Button('增加').onClick(() => {this.counter++}).margin(10)}.width('100%').padding(20)}
}

3.1.4 高级特性

1. 组件参数传递

@Component
struct AdvancedComponent {// 从父组件接收的属性@Prop title: string@State private description: string = ''build() {Column({ space: 10 }) {Text(this.title).fontSize(24)TextInput({ placeholder: '请输入描述' }).onChange((value: string) => {this.description = value})}}
}

2. 组件插槽(Slot)

@Component
struct SlotComponent {@BuilderParam content: () => voidbuild() {Column() {this.content()}.width('100%').backgroundColor('#f5f5f5')}
}// 使用组件插槽
@Component
struct ParentComponent {build() {SlotComponent() {Row() {Text('自定义内容')Image('icon.png')}}}
}

3.1.5 最佳实践

  1. 组件拆分原则
// 好的实践:功能单一,职责明确
@Component
struct UserAvatar {@Prop userName: string@Prop avatarUrl: stringbuild() {Stack() {Image(this.avatarUrl).width(50).height(50).borderRadius(25)Text(this.userName[0]).fontSize(20).fontColor(Color.White)}}
}// 使用组件
@Component
struct UserProfile {build() {Row() {UserAvatar({userName: "张三",avatarUrl: "avatar.png"})Text("其他信息")}}
}
  1. 生命周期使用建议
@Component
struct LifecycleComponent {@State private data: any = {}aboutToAppear() {// 初始化数据,订阅事件this.initData()}aboutToDisappear() {// 清理资源,取消订阅this.cleanUp()}private initData() {// 数据初始化逻辑}private cleanUp() {// 清理逻辑}build() {// UI渲染}
}

3.1.6 性能优化建议

  1. 状态管理优化
@Component
struct OptimizedComponent {// 使用私有变量存储不需要响应式更新的数据private staticData: string = 'static'// 只将需要触发更新的数据声明为@State@State dynamicData: number = 0build() {Column() {// 静态内容Text(this.staticData)// 动态内容Text(`${this.dynamicData}`)}}
}
  1. 条件渲染优化
@Component
struct ConditionalComponent {@State loading: boolean = true@State data: Array<string> = []build() {Column() {if (this.loading) {LoadingSpinner()} else {ForEach(this.data, (item) => {DataItem({ content: item })})}}}
}

3.2 @BuilderParam修饰符

3.2.1 基本概念

@BuilderParam用于声明自定义构建函数参数,使组件能够接收和渲染自定义内容。

3.2.2 使用场景

  1. 自定义列表项渲染

@Component
struct MainPage {
@State items: string[] = ['项目1', '项目2', '项目3']
@Builder myItemBuilder(item: string):void{}
@BuilderParam itemBuilder: (item: string) => void =  this.myItemBuilderbuild() {List() {ForEach(this.items, (item:string,idx:number) => {ListItem() {this.itemBuilder(item)}})}}
}// 使用示例
@Entry
@Component
struct TestCase {build() {Column(){MainPage({itemBuilder: (item:string) => {Row() {Text(item).width('100%').height('100%').backgroundColor(Color.Pink)}}})}}
}
  1. 可定制化容器组件
@Component
struct Container {@BuilderParam header?: () => void@BuilderParam content: () => void@BuilderParam footer?: () => voidbuild() {Column() {if (this.header) {this.header()}this.content()if (this.footer) {this.footer()}}}
}

3.2.3 注意事项与最佳实践

  1. 参数命名规范
// 推荐的命名方式
@BuilderParam headerBuilder: () => void
@BuilderParam contentBuilder: () => void
@BuilderParam footerBuilder: () => void// 不推荐的命名方式
@BuilderParam hdr: () => void
@BuilderParam cnt: () => void
  1. 性能考虑
@Component
struct PerformanceOptimizedList {// 使用私有变量缓存不常变化的构建函数@Builder myStaticBuilder() :void{Text('Static Content')
}@BuilderParam private staticBuilder:()=>void = this.myStaticBuilder@BuilderParam dynamicBuilder: () => voidbuild() {Column() {// 静态内容this.staticBuilder()// 动态内容this.dynamicBuilder()}}
}

四、状态管理类修饰符

4.1 @State修饰符

4.1.1 基本概念

@State是鸿蒙应用中最基础的状态管理修饰符,用于组件内部状态管理。当@State装饰的变量发生变化时,框架会自动重新渲染相关UI。

State变量改变
触发更新机制
计算差异
更新UI
完成渲染

4.1.2 使用规则

  1. 基本语法
interface IUser{name: string,age: number
}// 使用示例
@Entry
@Component
struct TestCase {// 基础类型@State count: number = 0// 对象类型@State user: IUser  = {name: 'tata',age: 25}// 数组类型@State list: string[] = ['item1', 'item2']build() {Column({ space: 20 }) {// 使用状态变量Text(`Count: ${this.count}`)Button('Add').onClick(() => {this.count++})Text(`User: ${this.user.name}, ${this.user.age}`)Button('Update User').onClick(() => {// 对象更新要使用新对象this.user = {name:this.user.name,age: this.user.age + 1}})}}
}

4.1.3 @State注意事项和最佳实践

  1. 状态初始化
@Component
struct StateInitDemo {// ✅ 推荐:直接初始化@State counter1: number = 0// ⚠️ 不推荐:延迟初始化可能导致问题@State counter2: numberaboutToAppear() {// 延迟初始化可能导致首次渲染问题this.counter2 = 0}
}
  1. 状态粒度控制
@Component
struct StateGranularityDemo {// ❌ 错误:粒度过大@State entirePage: {header: object,content: object,footer: object}// ✅ 正确:适当的状态粒度@State headerConfig: object@State contentList: array@State footerVisible: booleanbuild() {Column() {// UI实现}}
}

4.2 @Prop修饰符

4.2.1 基本概念

@Prop用于父子组件间的单向数据传递,子组件通过@Prop接收父组件传递的数据。

4.2.2 使用示例

// 子组件
@Component
struct ChildComponent {@Prop count: number  // 接收父组件传递的数值@Prop message: string  // 接收父组件传递的字符串build() {Column() {Text(`Count: ${this.count}`)Text(`Message: ${this.message}`)}}
}// 父组件
@Component
struct ParentComponent {@State parentCount: number = 0@State parentMessage: string = 'Hello'build() {Column() {// 传递属性给子组件ChildComponent({count: this.parentCount,message: this.parentMessage})Button('Update Parent').onClick(() => {this.parentCount++this.parentMessage = 'Updated'})}}
}

4.2.3 @Prop vs 普通变量对比

@Component
struct PropComparisonDemo {// @Prop装饰的变量@Prop propValue: number// 普通变量normalValue: numberbuild() {Column() {// @Prop变量会响应父组件的更新Text(`Prop Value: ${this.propValue}`)// 普通变量不会响应更新Text(`Normal Value: ${this.normalValue}`)}}
}
特性@Prop变量普通变量
数据流向单向(父到子)无数据流
响应更新自动响应不响应
可修改性本地可修改但不影响父组件可以自由修改
使用场景父子组件通信组件内部数据

4.2.4 @Prop的高级用法

  1. 默认值处理
@Component
struct PropDefaultDemo {// 使用装饰器提供默认值@Prop defaultValue: number = 100build() {Column() {Text(`Value: ${this.defaultValue}`)}}
}
  1. 属性监听与处理
@Component
struct PropWatchDemo {@Prop @Watch('onCountChange') count: number@State localCount: number = 0onCountChange() {// 当@Prop值变化时执行this.localCount = this.count * 2}build() {Column() {Text(`Prop Count: ${this.count}`)Text(`Local Count: ${this.localCount}`)}}
}

4.2.5 最佳实践

  1. 属性命名规范
@Component
struct PropNamingDemo {// ✅ 推荐:语义化命名@Prop isVisible: boolean@Prop userName: string@Prop itemCount: number// ❌ 避免:模糊的命名@Prop flag: boolean@Prop str: string@Prop num: number
}
  1. 类型安全
@Component
struct PropTypeDemo {// ✅ 推荐:明确的类型定义@Prop items: Array<{id: number,name: string}>// ❌ 避免:使用any类型@Prop data: any
}

4.3 @Link修饰符

4.3.1 基本概念

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

父组件状态
Link双向绑定
子组件状态
父组件UI更新
子组件UI更新

4.3.2 使用示例

// 子组件
@Component
struct LinkChildComponent {@Link countValue: number  // 双向绑定数据build() {Column() {Text(`Count: ${this.countValue}`)Button('在子组件中修改').onClick(() => {this.countValue++  // 修改会影响父组件})}}
}// 父组件
@Entry
@Component
struct TestCase {@State parentCount: number = 0build() {Column() {Text(`Parent Count: ${this.parentCount}`)LinkChildComponent({ countValue: $parentCount })Button('在父组件中修改').onClick(() => {this.parentCount++})}}
}

4.3.3 @Link vs @Prop 对比

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

4.3.4 @Link最佳实践

  1. 合理使用场景
@Component
struct FormComponent {// ✅ 适合使用@Link的场景:表单数据@Link formData: {username: string,password: string}build() {Column() {TextInput({ placeholder: '用户名' }).onChange((value) => {this.formData.username = value})TextInput({ placeholder: '密码' }).type(InputType.Password).onChange((value) => {this.formData.password = value})}}
}
  1. 避免过度使用
@Component
struct OptimizedComponent {// ✅ 只对需要双向绑定的数据使用@Link@Link editableData: string// ✅ 只读数据使用@Prop@Prop readOnlyData: string// ✅ 组件内部状态使用@State@State localState: number = 0build() {Column() {// 实现UI}}
}

4.4 @Provide/@Consume修饰符

4.4.1 基本概念

@Provide和@Consume用于实现跨组件层级的数据共享,避免多层props传递(即"prop drilling"问题)。

4.4.2 基础用法


interface IUser{name:string,role:string
}
// 顶层组件
@Entry
@Component
struct TestCase {@Provide('theme') theme: string = 'light'@Provide('user') userInfo:IUser  = {name: 'tata',role: 'admin'}build() {Column() {ConsumerComponent()}}
}// 消费组件(可以是任意层级的子组件)
@Component
struct ConsumerComponent {@Consume('theme') theme: string@Consume('user') userInfo: IUserbuild() {Column() {Text(`Current Theme: ${this.theme}`)Text(`User: ${this.userInfo.name}`)}}
}

4.4.3 高级特性

  1. 使用别名
@Component
struct AdvancedProvider {@Provide('systemTheme') theme: string = 'light'
}@Component
struct AdvancedConsumer {// 使用别名访问共享数据@Consume('systemTheme') currentTheme: stringbuild() {Column() {Text(`Theme: ${this.currentTheme}`)}}
}
  1. 多层级数据共享
@Component
struct AppRoot {@Provide('globalState') userInfo:IUser = {name:'tata',role:'admin'}build() {Column() {// 可以被任意深度的子组件访问DeepNestedComponent()}}
}

4.4.4 使用建议与最佳实践

  1. 合理的数据粒度
// ✅ 推荐:适当的粒度
@Component
struct GoodProvider {@Provide('userSettings') settings: UserSettings@Provide('appTheme') theme: Theme
}// ❌ 避免:过大的共享范围
@Component
struct BadProvider {@Provide('entireAppState') state: AppState
}
  1. 性能优化
@Component
struct OptimizedProvider {// 将频繁变化的数据和稳定数据分开@Provide('staticConfig') staticConfig: Config // 稳定数据@Provide('dynamicState') dynamicState: State // 变化数据build() {Column() {// 实现UI}}
}
  1. 错误处理
@Component
struct SafeConsumer {@Consume('data') data?: DataType  // 使用可选类型build() {Column() {if (this.data) {// 安全地使用数据Text(this.data.toString())} else {// 提供后备UIText('数据未就绪')}}}
}

4.5 @Watch修饰符

4.5.1 基本概念

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

状态变量改变
Watch监听
触发回调函数
执行自定义逻辑
更新UI/处理数据

4.5.2 基础用法

// 顶层组件
@Entry
@Component
struct TestCase {@State @Watch('onCountChange') count: number = 0@State message: string = ''onCountChange() {this.message = `计数变为 ${this.count.toString()}`}build() {Column({ space: 20 }) {Text(`Current count: ${this.count}`)Text(this.message)Button('Increment').onClick(() => {this.count++})}}
}

4.5.3 高级用法

  1. 监听多个属性
@Component
struct MultiWatchDemo {@State @Watch('onScoreChange') score: number = 0@State @Watch('onScoreChange') bonus: number = 0// 监听多个数值变化onScoreChange() {console.info(`Total: ${this.score + this.bonus}`)}build() {Column() {// UI实现}}
}
  1. 条件监听
@Component
struct ConditionalWatchDemo {@State @Watch('onValueChange') value: number = 0@State isEnabled: boolean = trueonValueChange(newValue: number, oldValue: number) {if (this.isEnabled) {// 只在启用状态下处理变化this.handleValueChange(newValue, oldValue)}}private handleValueChange(newVal: number, oldVal: number) {// 处理逻辑}build() {Column() {Switch().checked(this.isEnabled).onChange((value: boolean) => {this.isEnabled = value})}}
}

4.5.4 @Watch使用场景

  1. 表单验证
@Component
struct FormValidationDemo {@State @Watch('validateEmail') email: string = ''@State emailError: string = ''validateEmail(newValue: string) {const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/if (!emailRegex.test(newValue)) {this.emailError = '请输入有效的邮箱地址'} else {this.emailError = ''}}build() {Column({ space: 10 }) {TextInput({ placeholder: '请输入邮箱' }).onChange((value: string) => {this.email = value})if (this.emailError) {Text(this.emailError).fontSize(12).fontColor(Color.Red)}}}
}
  1. 数据同步
@Component
struct DataSyncDemo {@State @Watch('syncToServer') localData: IUser = {}async syncToServer(newValue: IUser) {try {await this.saveToServer(newValue)console.info('Data synced successfully')} catch (error) {console.error('Sync failed:', error)}}private async saveToServer(data: object) {// 实现服务器同步逻辑}build() {Column() {// UI实现}}
}

4.5.5 最佳实践

  1. 性能优化

@Component
struct WatchOptimizationDemo {@State @Watch('onDataChange') data: IUser = {name:'tata',role:'admin'}// ✅ 优化:添加防抖处理private debounceTimer: number = -1onDataChange() {if (this.debounceTimer !== -1) {clearTimeout(this.debounceTimer)}this.debounceTimer = setTimeout(() => {this.processDataChange(this.data)this.debounceTimer = -1}, 300)}private processDataChange(data: IUser) {// 处理数据变化}build() {Column() {// UI实现}}
}
  1. 错误处理
@Component
struct WatchErrorHandlingDemo {@State @Watch('onDataChange') data: IUser = {name:'tata',role:'admin'}onDataChange() {try {// 数据验证if (!this.isValidData(this.data)) {throw new Error('Invalid data format')}// 处理数据this.processData(this.data)} catch (error) {console.error('Error in watch handler:', error)// 恢复到之前的值// 显示错误提示this.showError(error.message)}}private isValidData(data: IUser): boolean {// 实现数据验证逻辑return true}private processData(data: IUser) {// 处理数据}private showError(message: string) {// 显示错误提示}build() {Column() {// UI实现}}
}

4.5.6 @Watch注意事项

  1. 避免无限循环
@Component
struct WatchCycleDemo {@State @Watch('onValueChange') value1: number = 0@State @Watch('onValue2Change') value2: number = 0// ❌ 错误:可能导致无限循环onValueChange() {this.value2++ // 触发value2的watch}onValue2Change() {this.value1++ // 触发value1的watch}// ✅ 正确:添加循环保护private updateCount: number = 0private readonly MAX_UPDATES: number = 3onSafeValueChange() {if (this.updateCount < this.MAX_UPDATES) {this.updateCount++this.value2++} else {this.updateCount = 0}}
}
  1. 同步与异步处理
@Component
struct WatchAsyncDemo {@State @Watch('onDataChange') data: object = {}// ✅ 处理异步操作async onDataChange(newValue: object) {try {await this.validateData(newValue)await this.saveData(newValue)} catch (error) {console.error('Async operation failed:', error)}}private async validateData(data: object): Promise<void> {// 异步数据验证}private async saveData(data: object): Promise<void> {// 异步保存数据}build() {Column() {// UI实现}}
}
  • @Watch 回调函数实际上不支持有效的参数传递
  • 回调函数中第一个参数是被监听属性的名称字符串

4.6 @Observed/@ObjectLink修饰符

4.6.1 基本概念

@Observed和@ObjectLink是用于对象类型数据的响应式管理修饰符:

  • @Observed:将一个类标记为可观察对象
  • @ObjectLink:用于在组件间建立对象的引用关系,实现对象级别的双向同步
Observed类
创建可观察对象
ObjectLink引用
子组件
响应式更新
父组件

4.6.2 基础用法

// 定义可观察类
@Observed
class Student {name: stringage: numberscores: number[]constructor(name: string, age: number) {this.name = namethis.age = agethis.scores = []}
}// 父组件
@Component
struct ParentComponent {// 创建可观察对象实例@State student: Student = new Student('tata', 18)build() {Column() {// 传递给子组件StudentCard({ studentInfo: this.student })Button('修改信息').onClick(() => {this.student.age++this.student.scores.push(100)})}}
}// 子组件
@Component
struct StudentCard {// 使用ObjectLink引用父组件的对象@ObjectLink studentInfo: Studentbuild() {Column() {Text(`姓名: ${this.studentInfo.name}`)Text(`年龄: ${this.studentInfo.age}`)ForEach(this.studentInfo.scores, (score:number) => {Text(`分数: ${score}`)})}}
}

4.6.3 关键点

  1. 类级别装饰器
// ✅ 正确:整个类使用 @Observed
@Observed
class Model {property1: stringproperty2: number
}// ❌ 错误:不能装饰属性
class WrongModel {@Observed property: string  // 这是错误的用法
}
  1. 嵌套对象处理
@Observed
class Parent {child: Child  // 如果 Child 需要观察,Child 类也需要使用 @Observed 装饰器
}@Observed
class Child {name: string
}
  1. 数组处理
@Observed
class TodoList {items: Array<TodoItem>  // TodoItem 类需要使用 @ObservedaddItem(item: TodoItem) {this.items.push(item)}
}@Observed
class TodoItem {content: stringcompleted: boolean
}

4.6.4 实际应用示例

// 定义观察类
@Observed
class Profile {name: stringage: numberconstructor(name: string, age: number) {this.name = namethis.age = age}
}// 父组件
@Component
struct ProfileManager {@State profile: Profile = new Profile('tata', 25)build() {Column() {// 传递给子组件ProfileEditor({ userProfile: this.profile })ProfileDisplay({ userProfile: this.profile })}}
}// 编辑组件
@Component
struct ProfileEditor {@ObjectLink userProfile: Profilebuild() {Column() {Button('修改年龄').onClick(() => {this.userProfile.age++  // 直接修改将触发更新})}}
}// 显示组件
@Component
struct ProfileDisplay {@ObjectLink userProfile: Profilebuild() {Column() {Text(`姓名: ${this.userProfile.name}`)Text(`年龄: ${this.userProfile.age}`)}}
}

4.6.5 注意事项

  1. @Observed 只能用于类声明
  2. 不能用于装饰类的属性
  3. 嵌套对象如需响应式,需要分别使用 @Observed 装饰器
  4. 配合 @ObjectLink 使用来实现组件间的数据同步
  5. 观察对象的属性修改会自动触发相关组件的更新

对比

让我详细对比这些修饰符的区别:

状态管理修饰符
State
Prop
Link
Observed/ObjectLink
组件内状态管理
单向数据流
双向数据绑定
对象级响应式

1. 使用场景对比

修饰符使用对象数据流向使用场景
@State基本类型/对象/数组组件内部管理组件内部状态
@Prop基本类型/对象/数组父 -> 子父组件向子组件传递数据
@Link基本类型/对象/数组双向父子组件双向数据同步
@Observed/@ObjectLink类实例多组件共享复杂对象的响应式管理

2. 具体示例对比

// @State:组件内部状态管理
@Component
struct StateExample {@State count: number = 0  // 组件内部状态build() {Column() {Text(`Count: ${this.count}`)Button('Add').onClick(() => this.count++)}}
}// @Prop:单向数据流
@Component
struct PropExample {@Prop title: string  // 从父组件接收数据build() {Text(this.title)}
}// @Link:双向数据绑定
@Component
struct LinkExample {@Link message: string  // 与父组件双向绑定build() {TextInput({ text: this.message }).onChange((value: string) => {this.message = value  // 修改会影响父组件})}
}// @Observed:对象响应式
@Observed
class User {name: stringage: numberconstructor(name: string, age: number) {this.name = namethis.age = age}
}@Component
struct ObservedExample {@State user: User = new User('tata', 25)build() {Column() {UserCard({ userInfo: this.user })  // 传递给子组件}}
}@Component
struct UserCard {@ObjectLink userInfo: User  // 引用观察对象build() {Column() {Text(`Name: ${this.userInfo.name}`)Button('Age++').onClick(() => {this.userInfo.age++  // 直接修改对象属性})}}
}

3. 特点对比

@State
  • 用于组件内部状态管理
  • 值变化会触发组件重新渲染
  • 可以管理任何类型的数据
@State count: number = 0
@State user: Object = {}
@State list: string[] = []
@Prop
  • 实现单向数据流
  • 子组件不能直接修改父组件数据
  • 父组件数据变化会更新子组件
// 父组件
@State title: string = 'Hello'
// 子组件使用
@Prop title: string
@Link
  • 实现双向数据绑定
  • 子组件可以直接修改数据
  • 数据变化双向同步
// 父组件
@State message: string = ''
// 子组件使用
@Link message: string
@Observed/@ObjectLink
  • 用于复杂对象的响应式管理
  • 自动跟踪对象属性变化
  • 支持多组件共享和同步
@Observed
class Model {// 整个类的属性都会被观察
}@ObjectLink model: Model  // 引用观察对象

4. 数据同步方式对比

// @State:组件内直接修改
@State value: number = 0
this.value = 1  // 直接赋值// @Prop:不能直接修改
@Prop title: string
this.title = 'new'  // ❌ 错误// @Link:双向同步
@Link count: number
this.count++  // ✅ 会同步到父组件// @Observed:对象属性修改
@ObjectLink user: User
this.user.name = 'new name'  // ✅ 自动触发更新

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/482494.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

phpmyadmin导出wordpress数据教程

网站搬家或网站修改&#xff0c;需要导出数据或备份数据&#xff0c;一般主机控制面板最常用phpmyadmin。下面这个是一个有详细图文操作步骤的phpmyadmin导出wordpress数据教程。 1、先登陆到你主机的管理面板&#xff0c;找到数据库&#xff0c;再找到phpmyadmin&#xff0c;…

阅读笔记——SVD本质+计算+应用

摘要&#xff1a;本文讨论了正交相似对角化的方法&#xff0c;几何含义&#xff1b;方阵&#xff0c;非方阵的奇异值分解的计算&#xff0c;矫正方法以及与正交相似对角化存在区别&#xff1b;最后讨论了奇异值分解的应用。 1.实对称矩阵A的变换是一种线性变换&#xff0c;对应…

Linux网络_网络协议_网络传输_网络字节序

一.协议 1.概念 协议&#xff08;Protocol&#xff09; 是一组规则和约定&#xff0c;用于定义计算机网络中不同设备之间如何进行通信和数据交换。协议规定了数据的格式、传输方式、传输顺序等详细规则&#xff0c;确保不同设备和系统能够有效地互联互通。 在网络通信中&#…

数据结构 (16)特殊矩阵的压缩存储

前言 特殊矩阵的压缩存储是数据结构中的一个重要概念&#xff0c;它旨在通过找出特殊矩阵中值相同的矩阵元素的分布规律&#xff0c;把那些呈现规律性分布的、值相同的多个矩阵元素压缩存储到一个存储空间中&#xff0c;从而节省存储空间。 一、特殊矩阵的定义 特殊矩阵是指具有…

ehr系统建设方案,人力资源功能模块主要分为哪些,hrm平台实际案例源码,springboot人力资源系统,vue,JAVA语言hr系统(源码)

eHR人力资源管理系统&#xff1a;功能强大的人力资源管理工具 随着企业规模的不断扩大和业务需求的多样化&#xff0c;传统的人力资源管理模式已无法满足现代企业的需求。eHR人力资源管理系统作为一种先进的管理工具&#xff0c;能够为企业提供高效、准确、实时的人力资源管理。…

搭建AD域服务器

搭建AD域服务器 使用深信服HCI搭建AD域服务器 1、新建虚拟机 2、填写参数 3、省略安装过程 4、进入服务器管理器 5、 6、 7、 8、 9、 10、 11、 12、 13、 14、 15、 16、 17、 18、 19、 20、 21、 22、 23、

MOH: MULTI-HEAD ATTENTION AS MIXTURE-OFHEAD ATTENTION

当前的问题 多头注意力使用多个头部可以提高模型的精度。然而&#xff0c;并不是所有的注意力头都具有同样的重要性。一些研究表明&#xff0c;许多注意力头可以被修剪而不影响准确性。 此外&#xff0c;在多头注意中&#xff0c;每个注意头并行操作&#xff0c;最终输出是所…

Spring boot之BeanDefinition介绍

在spring框架中IOC容器进行bean的创建和管理。Bean的创建是一个比较复杂的过程&#xff0c;它并不像我们创建对象一样只是直接new一下就行&#xff0c;虽然有些bean确实就是New一下。但在Spring中可以通过一些途径对bean进行增强扩展。在这个过程中&#xff0c;BeanDefinition作…

Ubuntu 服务器部署 Tomcat 并配置 SSL/TLS 证书

本文目录 准备登陆云服务器安装 Java下载 tomcat 包配置防火墙浏览器访问 Tomcat 默认页面以服务的形式运行 Tomcat创建 Tomcat 用户和组创建 systemd 服务文件启动 tomcat 服务 Tomcat webapps 文件目录部署一个静态网站tomcat 的配置文件 将域名解析到服务器Tomcat 配置 SSL/…

C++小问题

怎么分辨const修饰的是谁 是限定谁不能被改变的&#xff1f; 在C中&#xff0c;const关键字的用途和位置非常关键&#xff0c;它决定了谁不能被修改。const可以修饰变量、指针、引用等不同的对象&#xff0c;并且具体的作用取决于const的修饰位置。理解const的规则能够帮助我们…

PPT不能编辑,按钮都是灰色,怎么办?

PPT文件打开之后&#xff0c;发现无法编辑&#xff0c;再仔细查看发现工具栏中的功能按钮都是灰色的&#xff0c;无法使用&#xff0c;这是什么原因&#xff1f;该如何解决&#xff1f; 原因&#xff1a;无法编辑PPT文件&#xff0c;并且功能按钮都是灰色&#xff0c;这是因为…

相交链表和环形链表

&#xff08;一&#xff09;相交链表 相交链表 思路&#xff1a;先分别计算出A列表和B列表的长度&#xff0c;判断它们的尾节点是否相等&#xff0c;如果不相等就不相交&#xff0c;直接返回空。然后让两个列表中的长的列表先走它们的差距步&#xff0c;然后再一起走&#xff…

ARM架构下安装新版docker及docker-compose

一、常见CPU 架构&#xff1a; 二、环境信息 CPU架构操作系统配置HUAWEI Kunpeng 920 5220 aarch64openEuler 22.03 (LTS-SP3)64C128g15T 三、安装docker 3.1 二进制包下载 docker-ce 社区下载地址&#xff1a; wget https://mirrors.nju.edu.cn/docker-ce/linux/static/s…

LeetCode-315. Count of Smaller Numbers After Self

目录 题目描述 解题思路 【C】 【Java】 复杂度分析 LeetCode-315. Count of Smaller Numbers After Selfhttps://leetcode.com/problems/count-of-smaller-numbers-after-self/description/ 题目描述 Given an integer array nums, return an integer array counts whe…

【NLP 4、数学基础】

此去经年&#xff0c;应是良辰美景虚设 —— 24.11.28 一、线性代数 1.标量和向量 ① 标量 Scalar 一个标量就是一个单独的数 ② 向量 Vector 一个向量是一列数 可以把向量看作空间中的点&#xff0c;每个元素是不同坐标轴上的坐标 向量中有几个数&#xff0c;就叫作几维…

VideoBooth: Diffusion-based Video Generation with Image Prompts

VideoBooth: Diffusion-based Video Generation with Image Prompts 概括 文章提出了一个视频生成模型VideoBooth&#xff0c;输入一张图片和一个文本提示词&#xff0c;即可输出保持图片中物体且符合文本提示词要求的视频。 方法 粗-细两阶段设计&#xff1a;1&#xff09;…

Graphy 是一款终极、易于使用、功能齐全的 FPS 计数器、统计监视器和调试器,适用于您的 Unity 项目。

主要特点&#xff1a; Graph & Text: 图文&#xff1a; FPSMemory 记忆Audio 声音的Advanced device information 高级设备信息Debugging tools 调试工具 GitHub - Tayx94/graphy:Graphy 是适用于 Unity 项目的终极、易于使用、功能丰富的 FPS 计数器、统计监视器和调试…

ASP.NET Core 负载/压力测试

文章目录 一、第三方工具二、使用发布版本进行负载测试和压力测试 负载测试和压力测试对于确保 web 应用的性能和可缩放性非常重要。 尽管负载测试和压力测试的某些测试相似&#xff0c;但它们的目标不同。 负载测试&#xff1a;测试应用是否可以在特定情况下处理指定的用户负…

008静态路由-特定主机路由

按照如上配置&#xff0c;用192.168.0.1 电脑ping 192.168.1.1 发现能够ping通 用192.168.0.1 电脑ping 192.168.2.1 发现不能ping通 这是因为192.168.0.1 和 192.168.1.1 使用的是同一个路由器R1。 192.168.0.1 和 192.168.2.1 通信需要先经过R1&#xff0c;再经过R2 &#xf…

基于yolov4深度学习网络的排队人数统计系统matlab仿真,带GUI界面

目录 1.算法仿真效果 2.算法涉及理论知识概要 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; 仿真操作步骤可参考程序配套的操作视频。 2.算法涉及理论知识概要 在现代社会…