DEV Community

Freerain
Freerain

Posted on

鸿蒙 Next 中 Link 的用法详解

一、@link概述

在鸿蒙Next中,@Link装饰器用于在父子组件之间建立双向的数据同步关系。这意味着子组件中被@Link装饰的变量与其父组件中对应的数据源可以相互同步数据。从API version 9开始,该装饰器支持在ArkTS卡片中使用,从API version 11开始,支持在元服务中使用。

(一)同步机制

  1. 父组件中的数据源(如@State@StorageLink@Link)与子组件的@Link装饰变量之间实现双向数据同步。
  2. 任何一方数据的改变都会实时同步到另一方。

(二)限制条件

@Link装饰器不能在@Entry装饰的自定义组件中使用。

二、装饰器使用规则

  1. 参数:无参数。
  2. 同步类型:双向同步。
  3. 允许装饰的变量类型
    • 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类型校验。
  4. 被装饰变量的初始值:无,禁止本地初始化。

三、变量的传递/访问规则

  1. 从父组件初始化和更新
    • 必选,与父组件@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})。
  2. 用于初始化子组件:允许,可用于初始化常规变量、@State@Link@Prop@Provide
  3. 是否支持组件外访问:私有,只能在所属组件内访问。

四、观察变化和行为表现

(一)观察变化

  1. 基本类型(boolean、string、number):可以同步观察到数值的变化。
  2. class或Object类型:可以观察到赋值和属性赋值的变化(即Object.keys(observedObject)返回的所有属性)。
  3. 数组类型:可以观察到数组添加、删除、更新数组单元的变化。
  4. Date类型:可观察到Date整体的赋值,以及通过其接口更新属性的操作。
  5. Map类型(API11及以上):可观察到Map整体的赋值,以及通过其接口更新值的操作。
  6. Set类型(API11及以上):可观察到Set整体的赋值,以及通过其接口更新值的操作。

(二)框架行为

  1. 初始渲染
    • 执行父组件的build()函数创建子组件实例。
    • 必须指定父组件中的@State变量初始化子组件的@Link变量,二者保持同步。父组件的@State状态变量包装类传给子组件,子组件的@Link包装类注册自身指针给父组件的@State变量。
  2. 数据源更新(父组件到子组件)
    • 父组件@State变量变更后,遍历更新所有依赖它的系统组件和状态变量(如@Link包装类)。
    • 通知@Link包装类更新后,子组件中依赖@Link状态变量的系统组件也会更新,实现父组件对子组件的状态数据同步。
  3. @Link更新(子组件到父组件)
    • @Link更新后,调用父组件的@State包装类的set方法,将更新后的数值同步回父组件。
    • 子组件@Link和父组件@State分别遍历依赖的系统组件,进行对应的UI更新,实现子组件@Link同步回父组件@State

五、使用场景示例

(一)简单类型和类对象类型的@Link

父组件ShufflingContainer中的@State变量(简单类型yellowButtonProp和类对象类型greenButtonState)通过@Link与子组件GreenButtonYellowButton进行双向同步。在子组件中修改数据会同步到父组件,在父组件中修改数据也会同步到子组件。

(二)数组类型的@Link

父组件Parent@State数组arr通过@Link与子组件Childitems数组进行双向同步。子组件可以进行数组元素的添加、替换等操作并同步到父组件,父组件数组的变化也会同步到子组件。注意,@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与子组件Childname变量进行双向同步。在父组件或子组件中改变name的属性或类型,另一方会对应刷新。

六、常见问题及解决方法

(一)@Link装饰状态变量类型错误

子组件中@Link装饰的变量必须与数据源类型完全相同,且数据源需为被@State等装饰器装饰的状态变量。例如,若数据源为@State装饰的ClassA类型变量,子组件中@Link也应声明为ClassA类型,而不是其属性的类型。

(二)使用a.b(this.object)形式调用,不会触发UI刷新

@Link装饰的变量是Object类型,且在build方法内通过a.b(this.object)形式调用时(如通过静态方法或组件内部方法修改Object属性),无法触发UI刷新。解决方法是先对变量进行赋值,使修改操作作用于带有Proxy代理的变量,从而实现UI刷新。

Top comments (0)