一、@Link概述
在鸿蒙Next中,@Link
装饰器用于在父子组件之间建立双向的数据同步关系。这意味着子组件中被@Link
装饰的变量与其父组件中对应的数据源可以相互同步数据。从API version 9开始,该装饰器支持在ArkTS卡片中使用,从API version 11开始,支持在元服务中使用。
(一)同步机制
- 父组件中的数据源(如
@State
、@StorageLink
和@Link
)与子组件的@Link
装饰变量之间实现双向数据同步。 - 任何一方数据的改变都会实时同步到另一方。
(二)限制条件
@Link
装饰器不能在@Entry
装饰的自定义组件中使用。
二、装饰器使用规则
- 参数:无参数。
- 同步类型:双向同步。
允许装饰的变量类型
- Object、class、string、number、boolean、enum类型及其数组。
- 支持Date类型。
- API11及以上支持Map、Set类型。
- 支持ArkUI框架定义的联合类型Length、ResourceStr、ResourceColor类型。
- 类型必须被指定,且和双向绑定状态变量的类型相同。不支持any,API11及以上支持联合类型(如string | number、string | undefined或ClassA | null)。
- 当使用undefined和null的时候,建议显式指定类型,遵循TypeScript类型校验。
- 被装饰变量的初始值:无,禁止本地初始化。
三、变量的传递/访问规则
从父组件初始化和更新
- 必选,与父组件
@State
、@StorageLink
和@Link
建立双向绑定。 - 允许父组件中
@State
、@Link
、@Prop
、@Provide
、@Consume
、@ObjectLink
、@StorageLink
、@StorageProp
、@LocalStorageLink
和@LocalStorageProp
装饰变量初始化子组件@Link
。从API version 9开始,@Link
子组件从父组件初始化@State
的语法为Comp({ aLink: this.aState }),也支持Comp({aLink: $aState})。
- 必选,与父组件
- 用于初始化子组件:允许,可用于初始化常规变量、
@State
、@Link
、@Prop
、@Provide
。 - 是否支持组件外访问:私有,只能在所属组件内访问。
四、观察变化和行为表现
(一)观察变化
- 基本类型(boolean、string、number):可以同步观察到数值的变化。
- class或Object类型:可以观察到赋值和属性赋值的变化(即Object.keys(observedObject)返回的所有属性)。
- 数组类型:可以观察到数组添加、删除、更新数组单元的变化。
- Date类型:可观察到Date整体的赋值,以及通过其接口更新属性的操作。
- Map类型(API11及以上):可观察到Map整体的赋值,以及通过其接口更新值的操作。
- Set类型(API11及以上):可观察到Set整体的赋值,以及通过其接口更新值的操作。
(二)框架行为
初始渲染
- 执行父组件的
build()
函数创建子组件实例。 - 必须指定父组件中的
@State
变量初始化子组件的@Link
变量,二者保持同步。父组件的@State
状态变量包装类传给子组件,子组件的@Link
包装类注册自身指针给父组件的@State
变量。
- 执行父组件的
数据源更新(父组件到子组件)
- 父组件
@State
变量变更后,遍历更新所有依赖它的系统组件和状态变量(如@Link
包装类)。 - 通知
@Link
包装类更新后,子组件中依赖@Link
状态变量的系统组件也会更新,实现父组件对子组件的状态数据同步。
- 父组件
@Link
更新(子组件到父组件)@Link
更新后,调用父组件的@State
包装类的set
方法,将更新后的数值同步回父组件。- 子组件
@Link
和父组件@State
分别遍历依赖的系统组件,进行对应的UI更新,实现子组件@Link
同步回父组件@State
。
五、使用场景示例
(一)简单类型和类对象类型的@Link
父组件ShufflingContainer
中的@State
变量(简单类型yellowButtonProp
和类对象类型greenButtonState
)通过@Link
与子组件GreenButton
和YellowButton
进行双向同步。在子组件中修改数据会同步到父组件,在父组件中修改数据也会同步到子组件。
(二)数组类型的@Link
父组件Parent
的@State
数组arr
通过@Link
与子组件Child
的items
数组进行双向同步。子组件可以进行数组元素的添加、替换等操作并同步到父组件,父组件数组的变化也会同步到子组件。注意,@Link
和@State
的数组类型必须相同,不能将@Link
定义为单个元素类型去接收@State
数组中的数据项(若有此需求可参考@Prop
和@Observed
)。
(三)装饰Map类型变量(API11及以上)
子组件Child
的@Link
变量value
(类型为Map<number, string>
)与父组件MapSample2
的@State
变量message
进行双向同步。在子组件中可以对Map进行各种操作(如初始化、设置新值、清除、替换和删除元素等),视图会随之刷新,并且操作会同步到父组件。
(四)装饰Set类型变量(API11及以上)
子组件Child
的@Link
变量message
(类型为Set<number>
)与父组件SetSample1
的@State
变量message
进行双向同步。子组件对Set的操作(如初始化、添加元素、清除、删除元素等)会同步到父组件,父组件的变化也会同步到子组件,同时视图会相应刷新。
(五)使用双向同步机制更改本地其他变量
通过@Watch
装饰器,在子组件Child
中@Link
变量sourceNumber
的变化时,可以修改本地@State
变量memberMessage
,实现父子组件间变量的同步,但本地修改memberMessage
不会影响父组件中的变量。
(六)Link
支持联合类型实例
父组件Index
的@State
变量name
(类型为string | undefined
)通过@Link
与子组件Child
的name
变量进行双向同步。在父组件或子组件中改变name
的属性或类型,另一方会对应刷新。
六、常见问题及解决方法
(一)@Link
装饰状态变量类型错误
子组件中@Link
装饰的变量必须与数据源类型完全相同,且数据源需为被@State
等装饰器装饰的状态变量。例如,若数据源为@State
装饰的ClassA
类型变量,子组件中@Link
也应声明为ClassA
类型,而不是其属性的类型。
(二)使用a.b(this.object)
形式调用,不会触发UI刷新
当@Link
装饰的变量是Object类型,且在build
方法内通过a.b(this.object)
形式调用时(如通过静态方法或组件内部方法修改Object属性),无法触发UI刷新。解决方法是先对变量进行赋值,使修改操作作用于带有Proxy代理的变量,从而实现UI刷新。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。