HarmonyOS 鸿蒙Next中关于ObservedV2对象的序列化和反序列化的问题

HarmonyOS 鸿蒙Next中关于ObservedV2对象的序列化和反序列化的问题

ObservedV2序列化和反序列化的使用限制

  • @ObservedV2的类实例目前不支持使用JSON.stringify进行序列化。
  • 使用@ObservedV2@Trace装饰器的类,需通过new操作符实例化后,才具备被观测变化的能力。

以上描述来自官方文档

提出需求

  1. @ObservedV2的类实例可以序列化为json字符串
  2. json字符串可以反序列化为@ObservedV2的类实例,并具备被观测变化的能力
  3. 支持嵌套的可序列化和反序列化

@ObservedV2的类实例序列化为json字符串

方案一:JSON.stringify(obj).replaceAll(’_ob’,’’)

[@ObservedV2](/user/ObservedV2)
export class Contact{
  [@Trace](/user/Trace) name:string
  [@Trace](/user/Trace) value:string

  constructor(name: string, value: string) {
    this.name = name;
    this.value = value;
  }
}

[@ObservedV2](/user/ObservedV2)
export class User {
  [@Trace](/user/Trace)
  username: string
  [@Trace](/user/Trace)
  age: number
  [@Trace](/user/Trace)
  contacts:Contact[]

  constructor(username: string,age:number,contacts:Contact[]) {
    this.username = username;
    this.age = age;
    this.contacts = contacts
  }
}

把User对象序列化为json字符串

function userStringify(){
  let contacts:Contact[] = [new Contact('phone','123456')]
  let user:User = new User('alice',2.5,contacts)
  let jsonStr = JSON.stringify(user).replaceAll('__ob_','')
  Logger.debug(jsonStr)
}

日志打印结果:

{"username":"alice","age":2.5,"contacts":[{"name":"phone","value":"123456"}]}

方案二:使用class-transformer库序列化@ObservedV2对象

安装class-transformer

ohpm install class-transformer@0.5.1

直接序列化输出的数据错误,属性名称都变成__ob_xx

let jsonStr = JSON.stringify(instanceToPlain(user))
//日志打印结果
{"__ob_username":"alice","__ob_age":2.5,"__ob_contacts":[{"__ob_name":"phone","__ob_value":"123456"}]}

@Trace装饰的属性都要加上@Expose装饰器

import {instanceToPlain,Expose} from 'class-transformer';

[@ObservedV2](/user/ObservedV2)
export class Contact{
  [@Expose](/user/Expose)()
  [@Trace](/user/Trace)
  name:string

  [@Expose](/user/Expose)()
  [@Trace](/user/Trace)
  value:string

  constructor(name: string, value: string) {
    this.name = name;
    this.value = value;
  }
}

[@ObservedV2](/user/ObservedV2)
export class User {
  [@Expose](/user/Expose)()
  [@Trace](/user/Trace)
  username: string

  [@Expose](/user/Expose)()
  [@Trace](/user/Trace)
  age: number

  [@Expose](/user/Expose)()
  [@Trace](/user/Trace)
  contacts:Contact[]

  constructor(username: string,age:number,contacts:Contact[]) {
    this.username = username;
    this.age = age;
    this.contacts = contacts
  }
}

function userStringifyPlayB(){
  let contacts:Contact[] = [new Contact('phone','123456')]
  let user:User = new User('alice',2.5,contacts)
  //排除掉__ob_前缀的字段
  let jsonStr = JSON.stringify(instanceToPlain(user,{ excludePrefixes:['__ob_']}))
  Logger.debug(jsonStr)
}

日志打印结果:

{"username":"alice","age":2.5,"contacts":[{"name":"phone","value":"123456"}]}

ObservedV2的反序列化可移步我写的这一篇文章

[如何让从Http请求返回的JSON数据转换为@ObservedV2@Trace装饰的类的对象具有触发UI刷新的能力](https://developer.huawei.com/consumer/cn/forum/topic/0204187019579771145?fid=0109140870620153026)


更多关于HarmonyOS 鸿蒙Next中关于ObservedV2对象的序列化和反序列化的问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

6 回复
//排除掉__ob_前缀的字段
let jsonStr = JSON.stringify(instanceToPlain(user,{strategy:'excludeAll'}))

这样也可以

更多关于HarmonyOS 鸿蒙Next中关于ObservedV2对象的序列化和反序列化的问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


👍 {excludeExtrueousValues:true} 或者 {strategy:'excludeAll'} 都可以,但是需要注意的一点是 ObservedV2 装饰的类的所有属性都要加 @Expose 装饰器,不然序列化后的数据没有该属性,考虑到这一点这里就用的 { excludePrefixes:['__ob_']}。 当然如果 class 定义的属性名称类似这样的 __ob_id:number 就应该用你这种方式了。

是的,是的,'excludeAll’的话所有的属性都要加上@Expose,包含没有@Trace装饰的属性,搞忘求了就出bug, class的属性名称命名为__ob_xx,没人会这样命名吧!防御性编程吗🤣,

在HarmonyOS鸿蒙Next中,ObservedV2对象支持序列化和反序列化操作。序列化通过@ObservedV2装饰器的属性转换机制实现,将对象状态转换为可存储格式。反序列化时,系统自动重建对象状态并恢复响应式绑定。需使用ArkTS的序列化API,如JSON.stringify()和JSON.parse(),结合ObservedV2的特定方法处理装饰器属性。注意避免直接操作非公开接口,确保数据一致性。

针对ObservedV2对象的序列化问题,你提供的两种方案都很实用。

方案一使用字符串替换简单直接,适合简单场景,但需要注意可能误删其他字段中的"_ob"字符串。

方案二使用class-transformer库更为规范,通过@Expose装饰器明确指定需要序列化的属性,配合excludePrefixes选项过滤内部字段,代码可维护性更好。

对于反序列化需求,你提到的文章提供了完整解决方案,通过plainToInstance结合自定义实例化逻辑,确保反序列化后的对象保持响应式能力。

这两种方案都能满足嵌套序列化需求,建议根据项目复杂度选择:小型项目可用方案一,大型项目推荐方案二配合完整的序列化/反序列化流程。

回到顶部