HarmonyOS 实战:用 @Observed + @ObjectLink 玩转多组件实时数据更新

摘要

在鸿蒙(HarmonyOS)应用开发中,实时数据更新是一个绕不开的话题,尤其是在你封装了很多自定义组件、需要多个组件之间共享和同步数据的场景里。过去我们可能会依赖父子组件直接传参或全局状态管理,但这样写会让代码变得复杂、不易维护。鸿蒙提供了 @Observed@ObjectLink 装饰器,帮我们优雅地实现数据的实时更新和组件联动,开发体验非常顺滑。

引言

现在的鸿蒙应用场景越来越复杂,比如电商的商品详情和购物车同步、聊天应用的实时消息刷新、IoT 应用中的设备状态变更。这些都要求数据能在不同组件间实时更新,而且不能为了同步状态写一堆"搬运代码"。

在日常开发中,@Observed 负责让一个类的实例具备"可观察"的能力,一旦数据变化,引用它的组件就会自动刷新。@ObjectLink 则让子组件能够直接"订阅"父组件传下来的对象变化,而不需要手动再写回调去同步。

下面我们通过一个可运行的 Demo,把这套机制讲清楚。

基本原理

  • @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 应用,这套模式都能极大减少代码量,提高可维护性。

如果你现在的项目中有多个自定义组件需要共享数据,这套方法可以直接用起来,几乎不需要额外改动架构。

相关推荐
zhanshuo2 小时前
鸿蒙任务调度机制深度解析:优先级、时间片、多核与分布式的流畅秘密
harmonyos
小小小小小星8 小时前
ArkUI 5.0 核心特性与实战案例
harmonyos
奶糖不太甜11 小时前
鸿蒙多端开发:如何一次编写适配手机、手表、电视?
harmonyos
whysqwhw18 小时前
鸿蒙多线程
harmonyos
zhanshuo1 天前
鸿蒙文件系统全攻略:从设计原理到跨设备实战,带你玩转本地与分布式存储
harmonyos
zhanshuo1 天前
HarmonyOS 实战:一次性搞定全局初始化,从启动到多模块协同的完整方案
harmonyos
science138631 天前
鸿蒙抖音直播最严重的一个内存泄漏分析与解决
harmonyos
小小小小小星1 天前
鸿蒙开发之分布式能力:方法论与技术探索
harmonyos
li理1 天前
基础复用原理(@Reusable)
harmonyos