文章大纲
- 引言
- 一、组件间状态装饰器@Link 父子双向同步
- 1、使用规则
- 2、支持的观察变化的场景和ArkUI 刷新UI
- 3、@Link变量值初始化和更新机制
- 3.1、初始渲染:执行父组件的build()函数后将创建子组件的新实例。
- 3.2、@Link的数据源的更新:即父组件中状态变量更新,引起相关子组件的@Link的更新。
- 3.2、@Link的更新
- 二、@Link父子双向同步
- 1、简单类型和类对象类型的@Link
- 2、数组类型的@Link
引言
前一篇文章鸿蒙 入门——ArkUI 自定义组件间父到子单向同步的装饰器@Prop语法(三) 介绍了父组件——>子组件数据同步的装饰器@Prop,今天介绍的是父<——>子双向同步的装饰器@Link.
一、组件间状态装饰器@Link 父子双向同步
父组件中@State, @StorageLink和@Link 和子组件@Link可以建立双向数据同步,@Link 的变量不用初始化。
@Link装饰器不能在@Entry装饰的自定义组件中使用。
1、使用规则
2、支持的观察变化的场景和ArkUI 刷新UI
-
当装饰的数据类型为boolean、string、number类型时,可以同步观察到数值的变化。
-
当装饰的数据类型为class或者Object时,可以观察到赋值和属性赋值的变化,即Object.keys(observedObject)返回的所有属性。
-
当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化
-
当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性。
-
当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。
-
当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。
3、@Link变量值初始化和更新机制
@Link装饰的变量和其所属的自定义组件共享生命周期。父组件和拥有@Link变量的子组件初始渲染和双向更新流程如下(以父组件为@State为例):
3.1、初始渲染:执行父组件的build()函数后将创建子组件的新实例。
初始化过程如下:
- 必须指定父组件中的@State变量,用于初始化子组件的@Link变量。
- 子组件的@Link变量值与其父组件的数据源变量保持同步(双向数据同步)。
父组件的@State状态变量包装类通过构造函数传给子组件,子组件的@Link包装类拿到父组件的@State的状态变量后,将当前@Link包装类this指针注册给父组件的@State变量。
3.2、@Link的数据源的更新:即父组件中状态变量更新,引起相关子组件的@Link的更新。
处理步骤:
- 通过初始渲染的步骤可知,子组件@Link包装类把当前this指针注册给父组件。
- 父组件@State变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(比如@Link包装类)。
- 通知@Link包装类更新后,子组件中所有依赖@Link状态变量的系统组件(elementId)都会被通知更新。以此实现父组件对子组件的状态数据同步。
3.2、@Link的更新
当子组件中@Link更新后,处理步骤如下(以父组件为@State为例):
- @Link更新后,调用父组件的@State包装类的set方法,将更新后的数值同步回父组件。
- 子组件@Link和父组件@State分别遍历依赖的系统组件,进行对应的UI的更新。以此实现子组件@Link同步回父组件@State。
二、@Link父子双向同步
父子双向同步,父组件中@State, @StorageLink和@Link 和子组件@Link可以建立双向数据同步
@Link 的变量不用初始化
1、简单类型和类对象类型的@Link
class GreenButtonState {width: number = 0;constructor(width: number) {this.width = width;}
}
@Component
struct GreenButton {@Link greenButtonState: GreenButtonState;build() {Button('更新Green @Link属性').width(this.greenButtonState.width).height(100.0).backgroundColor('#00ff00').onClick(() => {if (this.greenButtonState.width < 700) {// 更新@Link 修饰的class的属性,变化可以被观察到并同步到父组件this.greenButtonState.width += 125;} else {// 更新class,变化可以被观察到同步回父组件this.greenButtonState = new GreenButtonState(100);}})}
}
@Component
struct YellowButton {@Link yellowButtonState: number;build() {Button('更新子组件的Yellow @Link').width(this.yellowButtonState).height(120.0).backgroundColor('#ffff00').onClick(() => {// 子组件的简单类型可以同步回父组件this.yellowButtonState += 50.0;})}
}@Entry
@Component
struct ShufflingContainer {@State greenButtonState: GreenButtonState = new GreenButtonState(300);@State yellowButtonProp: number = 100;build() {Column() {// 简单类型从父组件@State向子组件@Link数据同步Button('Parent View: Set@#State yellowButton').onClick(() => {this.yellowButtonProp = (this.yellowButtonProp < 700) ? this.yellowButtonProp + 100 : 100;})Divider()// class类型从父组件@State向子组件@Link数据同步Button('Parent View: Set@State GreenButton').onClick(() => {this.greenButtonState = new GreenButtonState(80);//this.greenButtonState.width = (this.greenButtonState.width < 700) ? this.greenButtonState.width + 100 : 100;})Divider()// class类型初始化@LinkGreenButton({ greenButtonState: this.greenButtonState })// 简单类型初始化@LinkYellowButton({ yellowButtonState: this.yellowButtonProp })}}
}
2、数组类型的@Link
@Component
struct Child2 {@Link items: number[];build() {Column() {Button(`Button1: push`).onClick(() => {this.items.push(this.items.length + 1);})Button(`Button2: replace whole item`).onClick(() => {this.items = [100, 200, 300];})}}
}@Component
struct Parent {@State arr: number[] = [1, 2, 3];build() {Column() {Child2({ items: $arr })ForEach(this.arr,(item:number) => {Text(`${item}`)},(item:number) => item.toString())}}
}