鸿蒙修饰符

文章目录

  • 一、引言
    • 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.mzph.cn/diannao/62378.shtml

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

相关文章

架构-微服务-服务配置

文章目录 前言一、配置中心介绍1. 什么是配置中心2. 解决方案 二、Nacos Config入门三、Nacos Config深入1. 配置动态刷新2. 配置共享 四、nacos服务配置的核心概念 前言 服务配置--Nacos Config‌ 微服务架构下关于配置文件的一些问题&#xff1a; 配置文件相对分散。在一个…

大米中的虫子检测-检测储藏的大米中是否有虫子 支持YOLO,VOC,COCO格式标注,4070张图片的数据集

大米中的虫子检测-检测储藏的大米中是否有虫子 支持YOLO&#xff0c;VOC&#xff0c;COCO格式标注&#xff0c;4070张图片的数据集 数据集分割 4070总图像数 训练组 87&#xff05; 3551图片 有效集 9&#xff05; 362图片 测试集 4% 157图片 预处理 自动定向…

Next.js -服务端组件如何渲染

#题引&#xff1a;我认为跟着官方文档学习不会走歪路 服务器组件渲染到客户端发生了什么&#xff1f; 请求到达服务器 用户在浏览器中请求一个页面。 Next.js 服务器接收到这个请求&#xff0c;并根据路由找到相应的页面组件。服务器组件的渲染 Next.js 识别出请求的页面包含…

架构03-事务处理

零、文章目录 架构03-事务处理 1、本地事务实现原子性和持久性 &#xff08;1&#xff09;事务类型 **本地事务&#xff1a;**单个服务、单个数据源**全局事务&#xff1a;**单个服务、多个数据源**共享事务&#xff1a;**多个服务、单个数据源**分布式事务&#xff1a;**多…

基于深度学习的手势识别算法

基于深度学习的手势识别算法 概述算法原理核心逻辑效果演示使用方式参考文献 概述 本文基于论文 [Simple Baselines for Human Pose Estimation and Tracking[1]](ECCV 2018 Open Access Repository (thecvf.com)) 实现手部姿态估计。 手部姿态估计是从图像或视频帧集中找到手…

硬件基础22 反馈放大电路

目录 一、反馈的基本概念与分类 1、什么是反馈 2、直流反馈与交流反馈 3、正反馈与负反馈 4、串联反馈与并联反馈 5、电压反馈与电流反馈 二、负反馈四种组态 1、电压串联负反馈放大电路 2、电压并联负反馈放大电路 3、电流串联负反馈放大电路 4、电流并联负反馈放大…

亚马逊开发视频人工智能模型,The Information 报道

根据《The Information》周三的报道&#xff0c;电子商务巨头亚马逊&#xff08;AMZN&#xff09;已开发出一种新的生成式人工智能&#xff08;AI&#xff09;&#xff0c;不仅能处理文本&#xff0c;还能处理图片和视频&#xff0c;从而减少对人工智能初创公司Anthropic的依赖…

Spring Boot教程之十二: Spring – RestTemplate

Spring – RestTemplate 由于流量大和快速访问服务&#xff0c;REST API越来越受欢迎。REST 不是一种协议或标准方式&#xff0c;而是一组架构约束。它也被称为 RESTful API 或 Web API。当发出客户端请求时&#xff0c;它只是通过 HTTP 将资源状态的表示传输给请求者或端点。传…

通过 JNI 实现 Java 与 Rust 的 Channel 消息传递

做纯粹的自己。“你要搞清楚自己人生的剧本——不是父母的续集&#xff0c;不是子女的前传&#xff0c;更不是朋友的外篇。对待生命你不妨再大胆一点&#xff0c;因为你好歹要失去它。如果这世上真有奇迹&#xff0c;那只是努力的另一个名字”。 一、crossbeam_channel 参考 cr…

CSS笔记(一)炉石传说卡牌设计1

目标 我要通过html实现一张炉石传说的卡牌设计 问题 其中必须就要考虑到各个元素的摆放&#xff0c;形状的调整来达到满意的效果。通过这个联系来熟悉一下CSS的基本操作。 1️⃣ 基本概念 在CSS里面有行元素&#xff0c;块元素&#xff0c;内联元素&#xff0c;常见的行元…

GAMES101:现代计算机图形学入门-笔记-09

久违的101图形学回归咯 今天的话题应该是比较轻松的&#xff1a;聊一聊在渲染中比较先进的topics Advanced Light Transport 首先是介绍一系列比较先进的光线传播方法&#xff0c;有无偏的如BDPT&#xff08;双向路径追踪&#xff09;&#xff0c;MLT&#xff08;梅特罗波利斯…

Oracle 数据库 IDENTITY 列

IDENTITY列是Oracle数据库12c推出的新特性。之所以叫IDENTITY列&#xff0c;是由于其支持ANSI SQL 关键字 IDENTITY&#xff0c;其内部实现还是使用SEQUENCE。 不过推出这个新语法也是应该的&#xff0c;毕竟MyQL已经有 AUTO_INCREMENT列&#xff0c;而SQL Server也已经有IDENT…

前端学习笔记之文件下载(1.0)

因为要用到这样一个场景&#xff0c;需要下载系统的使用教程&#xff0c;所以在前端项目中就提供了一个能够下载系统教程的一个按钮&#xff0c;供使用者进行下载。 所以就试着写一下这个功能&#xff0c;以一个demo的形式进行演示&#xff0c;在学习的过程中也发现了中文路径…

【阅读记录-章节4】Build a Large Language Model (From Scratch)

文章目录 4. Implementing a GPT model from scratch to generate text4.1 Coding an LLM architecture4.1.1 配置小型 GPT-2 模型4.1.2 DummyGPTModel代码示例4.1.3 准备输入数据并初始化 GPT 模型4.1.4 初始化并运行 GPT 模型 4.2 Normalizing activations with layer normal…

Python PDF转JPG图片小工具

Python PDF转JPG图片小工具 1.简介 将单个pdf装换成jpg格式图片 Tip: 1、软件窗口默认最前端&#xff0c;不支持调整窗口大小&#xff1b; 2、可通过按钮选择PDF文件&#xff0c;也可以直接拖拽文件到窗口&#xff1b; 3、转换质量有5个档位&#xff0c;&#xff08;0.25&a…

使用SOAtest进行功能回归测试

持续集成是将所有开发人员的工作副本合并到共享的主线上。这个过程使软件开发对开发人员来说更容易访问、更快、风险更小。 阅读这篇文章&#xff0c;让我们了解如何配置Parasoft SOAtest作为持续集成过程的一部分&#xff0c;来执行功能测试和回归测试。我们将介绍如何使用主…

ais_server 学习笔记

ais_server 学习笔记 一前序二、ais init1、时序图如下2. 初始化一共分为以下几个重要步骤&#xff1a;2.1.1、在ais_server中启动main函数&#xff0c;然后创建AisEngine&#xff0c;接着初始化AisEngine2.1.2、解析/var/camera_config.xml 文件&#xff0c;获取相关配置参数。…

L1G3000 任务-浦语提示词工程

基础任务 (完成此任务即完成闯关) 背景问题&#xff1a;近期相关研究指出&#xff0c;在处理特定文本分析任务时&#xff0c;语言模型的表现有时会遇到挑战&#xff0c;例如在分析单词内部的具体字母数量时可能会出现错误。任务要求&#xff1a;利用对提示词的精确设计&#xf…

Unity之一键创建自定义Package包

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity之一键创建自定义Package包 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&#xff01; …