
摘要
在鸿蒙(HarmonyOS)应用开发中,实时数据更新是一个绕不开的话题,尤其是在你封装了很多自定义组件、需要多个组件之间共享和同步数据的场景里。过去我们可能会依赖父子组件直接传参或全局状态管理,但这样写会让代码变得复杂、不易维护。鸿蒙提供了 @Observed 和 @ObjectLink 装饰器,帮我们优雅地实现数据的实时更新和组件联动,开发体验非常顺滑。
引言
现在的鸿蒙应用场景越来越复杂,比如电商的商品详情和购物车同步、聊天应用的实时消息刷新、IoT 应用中的设备状态变更。这些都要求数据能在不同组件间实时更新,而且不能为了同步状态写一堆"搬运代码"。
在日常开发中,@Observed 负责让一个类的实例具备"可观察"的能力,一旦数据变化,引用它的组件就会自动刷新。@ObjectLink 则让子组件能够直接"订阅"父组件传下来的对象变化,而不需要手动再写回调去同步。
下面我们通过一个可运行的 Demo,把这套机制讲清楚。
用 @Observed + @ObjectLink 实现实时数据更新
基本原理
- @Observed:让一个类的实例变成可观察对象,当它的属性发生变化时,会通知引用它的 UI 组件重新渲染。
- @ObjectLink:用于子组件属性绑定,让子组件可以感知父组件传入的对象变化。
代码示例
ts
// ViewModel.ts
@Observed
export class MyViewModel {
title: string = ""
constructor(title: string) {
this.title = title
}
}
// OtherComponent.ets
@Component
export struct OtherComponent {
@ObjectLink vm: MyViewModel
build() {
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。
ts
@Observed
export class CartItem {
count: number = 1
}
@Component
export struct ProductDetail {
@ObjectLink item: CartItem
build() {
Column() {
Button("增加数量")
.onClick(() => this.item.count++)
}
}
}
@Component
export struct CartBar {
@ObjectLink item: CartItem
build() {
Text("数量: " + this.item.count)
}
}
场景 2:聊天应用的实时消息
描述:在聊天页面发送消息,消息列表组件应当实时刷新。
实现思路:
- 用
@Observed
包装一个MessageList
,内部是一个数组。 - 消息输入框组件发送消息后,直接修改
MessageList
,消息列表组件自动更新。
ts
@Observed
class MessageList {
messages: string[] = []
}
@Component
struct ChatInput {
@ObjectLink msgList: MessageList
build() {
Button("发送")
.onClick(() => {
this.msgList.messages.push("新消息 " + Date.now())
})
}
}
@Component
struct ChatList {
@ObjectLink msgList: MessageList
build() {
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 应用,这套模式都能极大减少代码量,提高可维护性。
如果你现在的项目中有多个自定义组件需要共享数据,这套方法可以直接用起来,几乎不需要额外改动架构。