大连全瓷种植牙齿制作中心 发表于 2024-9-14 00:57:45

【鸿蒙实战开发】@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变革

@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变革
媒介

为什么要有@Observed装饰器和@ObjectLink装饰器?
在@Prop,@Link,@Provide与@Consume这几个装饰器仅能观察到第一层的变革,在实际应用开发中,应用会根据开发必要,封装本身的数据模子。对于多层嵌套的情况,比如二维数组,或者数组项class,或者class的属性是class,他们的第二层的属性变革是无法观察到的。这就引出了@Observed/@ObjectLink装饰器的作用。
概述

@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中举行双向数据同步:
●被@Observed装饰的类,可以被观察到属性的变革;
●子组件中@ObjectLink装饰器装饰的状态变量用于吸收@Observed装饰的类的实例,和父组件中对应的状态变量创建双向数据绑定。这个实例可以是数组中的被@Observed装饰的项,或者是class object中的属性,这个属性同样也必要被@Observed装饰。
●单独使用@Observed是没有任何作用的,必要搭配@ObjectLink或者@Prop使用。
注意:

   使用@Observed装饰class会改变class原始的原型链,@Observed和其他类装饰器装饰同一个class可能会带来问题。
@ObjectLink装饰器不能在@Entry装饰的自界说组件中使用。
装饰器阐明

https://i-blog.csdnimg.cn/direct/e1bf3252c9254d4187916e25e0e3c508.png
@ObjectLink装饰的变量不能被赋值,假如要使用赋值操纵,可以使用@Prop。
●@Prop装饰的变量和数据源的关系是是单向同步,@Prop装饰的变量在本地拷贝了数据源,所以它允许本地更改,假如父组件中的数据源有更新,@Prop装饰的变量本地的修改将被覆盖;
●@ObjectLink装饰的变量和数据源的关系是双向同步,@ObjectLink装饰的变量相当于指向数据源的指针。克制对@ObjectLink装饰的变量赋值,假如一旦发生@ObjectLink装饰的变量的赋值,则同步链将被打断。因为@ObjectLink装饰的变量通过数据源(Object)引用来初始化。对于实现双向数据同步的@ObjectLink,赋值相当于更新父组件中的数组项或者class的属性,TypeScript/JavaScript不能实现,会发生运行时报错。
框架举动

●初始渲染:
●@Observed装饰的class的实例会被不透明的代理对象包装,代理了class上的属性的setter和getter方法
●子组件中@ObjectLink装饰的从父组件初始化,吸收被@Observed装饰的class的实例,@ObjectLink的包装类会将本身注册给@Observed class。
●属性更新:当@Observed装饰的class属性改变时,会走到代理的setter和getter,然后遍历依靠它的@ObjectLink包装类,通知数据更新。
示例:

嵌套对象和数组
@Observed
class Person{
name:string
age:number
gf:Person
constructor(name:string,age:number,gf?:Person){
    this.name=name
    this.age=age
    this.gf=gf
}
}

@Component
struct Child{
@ObjectLink p:Person
build() {
    Column(){
      Text(`${this.p.name}:${this.p.age}`)
    }
}
}

@Entry
@Component
struct Parent{
@State p:Person=new Person('Tom',21,new Person('Rose',18))
@State gfs:Person[]=
build() {
    Column(){
      Child({p:this.p.gf})
      .onClick(()=>this.p.gf.age++)
      Text('-------------------')
      ForEach(
      this.gfs,
      p=>{
          Child({p:p}).onClick(()=>this.p.age++)
      }
      )
    }
}
}
在子组件中给@ObjectLink装饰的变量赋值是不允许的。
@Observed
class ClassA {
public c: number = 0;
constructor(c: number) {
    this.c = c;
}
}

@Component
struct ObjectLinkChild {
@ObjectLink testNum: ClassA;

build() {
    Text(`ObjectLinkChild testNum ${this.testNum.c}`)
      .onClick(() => {
      // ObjectLink不能被赋值 这是不允许的,对于实现双向数据同步的@ObjectLink,赋值相当于要更新父组件中的数组项或者class的属性,这个对于 TypeScript/JavaScript是不能实现的。框架对于这种行为会发生运行时报错。
      this.testNum = new ClassA(47);
      // 可以对ObjectLink装饰对象的属性赋值
      //this.testNum.c = 47;
      })
}
}

@Entry
@Component
struct Parent {
@State testNum: ClassA[] = ;
build() {
    Column() {
      Text(`Parent testNum ${this.testNum.c}`)
      .onClick(() => {
          this.testNum.c += 1;
      })
      ObjectLinkChild({ testNum: this.testNum })
    }
}
}
@Prop与@ObjectLink的差别

@ObjectLink装饰的变量是对数据源的引用
https://i-blog.csdnimg.cn/direct/0d3e2c4329834ced987650f4dd5821e4.png
代码示例:
let nextId = 1;

@Observed
class SubCounter {
counter: number;

constructor(c: number) {
    this.counter = c;
}
}

@Observed
class ParentCounter {
id: number;
counter: number;
subCounter: SubCounter;
incrCounter() {
    this.counter++;
}

incrSubCounter(c: number) {
    this.subCounter.counter += c;
}

setSubCounter(c: number): void {
    this.subCounter.counter = c;
}

constructor(c: number) {
    this.id = nextId++;
    this.counter = c;
    this.subCounter = new SubCounter(c);
}
}

@Component
struct CounterComp {
@ObjectLink value: ParentCounter;

build() {
    Column({ space: 10 }) {
      CountChild({ subValue: this.value.subCounter })
      Text(`this.value.counter:increase 7 `)
      .fontSize(30)
      .onClick(() => {
          // click handler, Text(`this.subValue.counter: ${this.subValue.counter}`) will update
          this.value.incrSubCounter(7);
      })
      Divider().height(2)
    }
}
}

@Component
struct CountChild {
@ObjectLink subValue: SubCounter;

build() {
    Text(`this.subValue.counter: ${this.subValue.counter}`)
      .fontSize(30)
}
}

@Entry
@Component
struct ParentComp {
@State counter: ParentCounter[] = ;

build() {
    Row() {
      Column() {
      CounterComp({ value: this.counter })
      CounterComp({ value: this.counter })
      CounterComp({ value: this.counter })
      Divider().height(5)
      ForEach(this.counter,
          (item: ParentCounter) => {
            CounterComp({ value: item })
          },
          (item: ParentCounter) => item.id.toString()
      )
      Divider().height(5)
      Text('Parent: reset entire counter')
          .fontSize(20).height(50)
          .onClick(() => {
            this.counter = ;
          })
      Text('Parent: incr counter.counter')
          .fontSize(20).height(50)
          .onClick(() => {
            this.counter.incrCounter();
            this.counter.incrSubCounter(10);
          })
      Text('Parent: set.counter to 10')
          .fontSize(20).height(50)
          .onClick(() => {
            this.counter.setSubCounter(10);
          })
      }
    }
}
}
@Prop装饰变量时会举行深拷贝

假如用@Prop替代@ObjectLink。点击第一个click handler,UI革新正常。但是点击第二个onClick变乱,@Prop 对变量做了一个本地拷贝,CounterComp的第一个Text并不会革新。
this.value.subCounter和this.subValue并不是同一个对象。所以this.value.subCounter的改变,并没有改变this.subValue的拷贝对象,Text(
   this.subValue.counter: ${this.subValue.counter}
)不会革新。
https://i-blog.csdnimg.cn/direct/ee8b58e5cf7548bbb6f88c923d5c3faf.png
代码示例:
@Component
struct CounterComp {
@Prop value: ParentCounter = new ParentCounter(0);
@Prop subValue: SubCounter = new SubCounter(0);
build() {
    Column({ space: 10 }) {
      Text(`this.subValue.counter: ${this.subValue.counter}`)
      .fontSize(20)
      .onClick(() => {
          // 1st click handler
          this.subValue.counter += 7;
      })
      Text(`this.value.counter:increase 7 `)
      .fontSize(20)
      .onClick(() => {
          // 2nd click handler
          this.value.incrSubCounter(7);
      })
      Divider().height(2)
    }
}
}
总结:

每个装饰器都有本身可以观察的能力,并不是全部的改变都可以被观察到,只有可以被观察到的变革才会举行UI更新。@Observed装饰器可以观察到嵌套对象的属性变革,其他装饰器仅能观察到第二层的变革。
●@ObjectLink和@Observed类装饰器用于在涉及嵌套对象或数组的场景中举行双向数据同步:
●被@Observed装饰的类,可以被观察到属性的变革;
●子组件中@ObjectLink装饰器装饰的状态变量用于吸收@Observed装饰的类的实例,和父组件中对应的状态变量创建双向数据绑定。
单独使用@Observed是没有任何作用的,必要搭配@ObjectLink或者@Prop使用。
@ObjectLink装饰的变量和数据源的关系是双向同步,@ObjectLink装饰的变量相当于指向数据源的指针。克制对@ObjectLink装饰的变量赋值,假如一旦发生@ObjectLink装饰的变量的赋值,则同步链将被打断。
@Prop与@ObjectLink的差别:

@ObjectLink装饰的变量是对数据源的引用
@Prop装饰变量时会举行深拷贝
写在最后

总的来说,华为鸿蒙不再兼容安卓,对中年步调员来说是一个寻衅,也是一个机会。随着鸿蒙的不断发展以及国家的大力支持,将来鸿蒙职位肯定会迎来一个大的发作,只有积极应对变革,不断学习和提升本身,我们才气在这个变革的期间中立于不败之地。
●假如你觉得这篇内容对你还蛮有资助,我想约请你帮我两个小忙:
●点赞,转发,有你们的 『点赞和批评』,才是我创造的动力。
●关注小编,同时可以等待后续文章ing ,不定期分享原创知识。
https://i-blog.csdnimg.cn/direct/04755945b7d840969f7fb35325948cbf.gif#pic_center

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【鸿蒙实战开发】@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变革