摘要
在鸿蒙(HarmonyOS)应用开发中,实时数据更新是一个绕不开的话题,尤其是在你封装了很多自定义组件、需要多个组件之间共享和同步数据的场景里。过去我们可能会依赖父子组件直接传参或全局状态管理,但这样写会让代码变得复杂、不易维护。鸿蒙提供了 @Observed 和 @ObjectLink 装饰器,帮我们优雅地实现数据的实时更新和组件联动,开发体验非常顺滑。
引言
现在的鸿蒙应用场景越来越复杂,比如电商的商品详情和购物车同步、聊天应用的实时消息刷新、IoT 应用中的设备状态变更。这些都要求数据能在不同组件间实时更新,而且不能为了同步状态写一堆“搬运代码”。
在日常开发中,@Observed 负责让一个类的实例具备“可观察”的能力,一旦数据变化,引用它的组件就会自动刷新。@ObjectLink 则让子组件能够直接“订阅”父组件传下来的对象变化,而不需要手动再写回调去同步。
下面我们通过一个可运行的 Demo,把这套机制讲清楚。
用 @Observed + @ObjectLink 实现实时数据更新
基本原理
- @Observed:让一个类的实例变成可观察对象,当它的属性发生变化时,会通知引用它的 UI 组件重新渲染。
- @ObjectLink:用于子组件属性绑定,让子组件可以感知父组件传入的对象变化。
代码示例
// ViewModel.ts
@Observed
export class MyViewModel {title: string = ""constructor(title: string) {this.title = title}
}// OtherComponent.ets
@Component
export struct OtherComponent {@ObjectLink vm: MyViewModelbuild() {Row() {Text(this.vm.title).fontSize(20).fontWeight(FontWeight.Bold).margin(10)}.width("100%").height(60).backgroundColor("#eeeeee").justifyContent(FlexAlign.Center).alignItems(VerticalAlign.Center)}
}// MyComponent.ets
@Entry
@Component
export struct MyComponent {@State vm: MyViewModel = new MyViewModel("初始标题")build() {Column() {OtherComponent({ vm: this.vm }).onClick(() => {this.vm.title = "标题已更新 " + new Date().toLocaleTimeString()})Button("点击更新标题").margin(10).onClick(() => {this.vm.title = "按钮触发更新 " + new Date().toLocaleTimeString()})}.width("100%").height("100%")}
}
代码解析
MyViewModel
- 用
@Observed
修饰,让它的属性具备响应式更新能力。 - 改变
title
会自动触发 UI 组件刷新。
OtherComponent
- 用
@ObjectLink
接收父组件传入的vm
,并实时订阅它的变化。 - 不需要手动写事件监听,只要数据变化,UI 就会刷新。
MyComponent
- 用
@State
声明一个可响应的MyViewModel
实例,并传给子组件。 - 父组件点击区域或者按钮都会修改
vm.title
,从而触发子组件刷新。
场景应用
场景 1:商品详情与购物车同步
描述:在电商应用中,用户在商品详情页修改购买数量,购物车组件的数量显示也需要立刻变化。
实现思路:
- 将商品数量信息放到一个
@Observed
的 ViewModel 中。 - 详情页和购物车组件通过
@ObjectLink
共享这个 ViewModel。
@Observed
export class CartItem {count: number = 1
}@Component
export struct ProductDetail {@ObjectLink item: CartItembuild() {Column() {Button("增加数量").onClick(() => this.item.count++)}}
}@Component
export struct CartBar {@ObjectLink item: CartItembuild() {Text("数量: " + this.item.count)}
}
场景 2:聊天应用的实时消息
描述:在聊天页面发送消息,消息列表组件应当实时刷新。
实现思路:
- 用
@Observed
包装一个MessageList
,内部是一个数组。 - 消息输入框组件发送消息后,直接修改
MessageList
,消息列表组件自动更新。
@Observed
class MessageList {messages: string[] = []
}@Component
struct ChatInput {@ObjectLink msgList: MessageListbuild() {Button("发送").onClick(() => {this.msgList.messages.push("新消息 " + Date.now())})}
}@Component
struct ChatList {@ObjectLink msgList: MessageListbuild() {Column() {ForEach(this.msgList.messages, (msg) => Text(msg))}}
}
场景 3:IoT 设备状态面板
描述:多个组件显示同一设备的温度、湿度、电池电量,任意组件更新数据时其他组件同步变化。
实现思路:
- 用
@Observed
包装DeviceStatus
对象。 - 传递给各个子组件,通过
@ObjectLink
绑定。
QA 环节
Q1:@Observed 和 @State 有什么区别?
@Observed
用于类的实例,使它变成可观察对象,适合跨组件共享。@State
用于组件内的变量,适合管理本地状态。
Q2:为什么要用 @ObjectLink,而不是直接传值?
- 直接传值是浅拷贝,不会触发子组件刷新。
@ObjectLink
会建立对象引用,保证数据变化实时传递。
Q3:如果多个组件要共享数据,该怎么组织?
- 建议抽一个 ViewModel,用
@Observed
修饰,在需要的地方通过@ObjectLink
引用。
总结
在鸿蒙应用开发中,@Observed + @ObjectLink 是处理实时数据更新的“黄金搭档”。它们的组合能让我们轻松在多个组件间同步数据,而不用手动写一堆事件监听或状态同步逻辑。在实际项目中,不管是电商、聊天还是 IoT 应用,这套模式都能极大减少代码量,提高可维护性。
如果你现在的项目中有多个自定义组件需要共享数据,这套方法可以直接用起来,几乎不需要额外改动架构。