当前位置: 代码网 > 科技>操作系统>鸿蒙系统 > OpenHarmony后代组件双向同步,跨层级传递:@Provide装饰器和@Consume装饰器

OpenHarmony后代组件双向同步,跨层级传递:@Provide装饰器和@Consume装饰器

2024年08月04日 鸿蒙系统 我要评论
# OpenHarmony后代组件双向同步,跨层级传递:@Provide装饰器和@Consume装饰器 @Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。 其中@Provide装饰的变量是在祖先节点中,可以理解为被“提供”给后代的状态变量。@Consume装饰的变量是在后代组件中,去“消费(绑...

openharmony后代组件双向同步,跨层级传递:@provide装饰器和@consume装饰器

@provide和@consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@provide和@consume摆脱参数传递机制的束缚,实现跨层级传递。

其中@provide装饰的变量是在祖先节点中,可以理解为被“提供”给后代的状态变量。@consume装饰的变量是在后代组件中,去“消费(绑定)”祖先节点提供的变量。

说明:

从api version 9开始,这两个装饰器支持在arkts卡片中使用。

概述

@provide/@consume装饰的状态变量有以下特性:

​ ● @provide装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,@provide的方便之处在于,开发者不需要多次在组件之间传递变量。

​ ● 后代通过使用@consume去获取@provide提供的变量,建立在@provide和@consume之间的双向数据同步,与@state/@link不同的是,前者可以在多层级的父子组件之间传递。

​ ● @provide和@consume可以通过相同的变量名或者相同的变量别名绑定,建议类型相同,否则会发生类型隐式转换,从而导致应用行为异常。

// 通过相同的变量名绑定
@provide a: number = 0;
@consume a: number;

// 通过相同的变量别名绑定
@provide('a') b: number = 0;
@consume('a') c: number;

@provide和@consume通过相同的变量名或者相同的变量别名绑定时,@provide修饰的变量和@consume修饰的变量是一对多的关系。不允许在同一个自定义组件内,包括其子组件中声明多个同名或者同别名的@provide装饰的变量,@provide的属性名或别名需要唯一且确定,如果声明多个同名或者同别名的@provide装饰的变量,会发生运行时报错。

装饰器说明

@state的规则同样适用于@provide,差异为@provide还作为多层后代的同步源。

@provide变量装饰器 说明
装饰器参数 别名:常量字符串,可选。如果指定了别名,则通过别名来绑定变量;如果未指定别名,则通过变量名绑定变量。
同步类型 双向同步。从@provide变量到所有@consume变量以及相反的方向的数据同步。双向同步的操作与@state和@link的组合相同。
允许装饰的变量类型 object、class、string、number、boolean、enum类型,以及这些类型的数组。支持date类型。支持类型的场景请参考观察变化。不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。必须指定类型。@provide变量的@consume变量的类型必须相同。说明:不支持length、resourcestr、resourcecolor类型,length、resourcestr、resourcecolor为简单类型和复杂类型的联合类型。
被装饰变量的初始值 必须指定。
@consume变量装饰器 说明
装饰器参数 别名:常量字符串,可选。如果提供了别名,则必须有@provide的变量和其有相同的别名才可以匹配成功;否则,则需要变量名相同才能匹配成功。
同步类型 双向:从@provide变量(具体请参见@provide)到所有@consume变量,以及相反的方向。双向同步操作与@state和@link的组合相同。
允许装饰的变量类型 object、class、string、number、boolean、enum类型,以及这些类型的数组。支持date类型。支持类型的场景请参考观察变化。不支持any,不允许使用undefined和null。必须指定类型。@provide变量的@consume变量的类型必须相同。说明:@consume装饰的变量,在其父节点或者祖先节点上,必须有对应的属性和别名的@provide装饰的变量。
被装饰变量的初始值 无,禁止本地初始化。

变量的传递/访问规则说明

@provide传递/访问 说明
从父组件初始化和更新 可选,允许父组件中常规变量(常规变量对@prop赋值,只是数值的初始化,常规变量的变化不会触发ui刷新,只有状态变量才能触发ui刷新)、@state、@link、@prop、@provide、@consume、@objectlink、@storagelink、@storageprop、@localstoragelink和@localstorageprop装饰的变量装饰变量初始化子组件@provide。
用于初始化子组件 允许,可用于初始化@state、@link、@prop、@provide。
和父组件同步 否。
和后代组件同步 和@consume双向同步。
是否支持组件外访问 私有,仅可以在所属组件内访问。

图1 @provide初始化规则图示
file

@consume传递/访问 说明
从父组件初始化和更新 禁止。通过相同的变量名和alias(别名)从@provide初始化。
用于初始化子组件 允许,可用于初始化@state、@link、@prop、@provide。
和祖先组件同步 和@provide双向同步。
是否支持组件外访问 私有,仅可以在所属组件内访问

图2 @consume初始化规则图示
file

观察变化和行为表现

观察变化

​ ● 当装饰的数据类型为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的属性。

@component
struct compd {

  @consume selecteddate: date;

  build() {
    column() {
      button(`child increase the day by 1`)
        .onclick(() => {
          this.selecteddate.setdate(this.selecteddate.getdate() + 1)
        })
      button('child update the new date')
        .margin(10)
        .onclick(() => {
          this.selecteddate = new date('2023-09-09')
        })
      datepicker({
        start: new date('1970-1-1'),
        end: new date('2100-1-1'),
        selected: this.selecteddate
      })
    }
  }
}

@entry
@component
struct compa {

  @provide selecteddate: date = new date('2021-08-08')

  build() {
    column() {
      button('parent increase the day by 1')
        .margin(10)
        .onclick(() => {
          this.selecteddate.setdate(this.selecteddate.getdate() + 1)
        })
      button('parent update the new date')
        .margin(10)
        .onclick(() => {
          this.selecteddate = new date('2023-07-07')
        })
      datepicker({
        start: new date('1970-1-1'),
        end: new date('2100-1-1'),
        selected: this.selecteddate
      })
      compd()
    }
  }
}

框架行为

​ 1. 初始渲染:

​ a. @provide装饰的变量会以map的形式,传递给当前@provide所属组件的所有子组件;

​ b. 子组件中如果使用@consume变量,则会在map中查找是否有该变量名/alias(别名)对应的@provide的变量,如果查找不到,框架会抛出js error;

​ c. 在初始化@consume变量时,和@state/@link的流程类似,@consume变量会保存在map中查找到的@provide变量,并把自己注册给@provide。

​ 2. 当@provide装饰的数据变化时:

​ a. 通过初始渲染的步骤可知,子组件@consume已把自己注册给父组件。父组件@provide变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(@consume);

​ b. 通知@consume更新后,子组件所有依赖@consume的系统组件(elementid)都会被通知更新。以此实现@provide对@consume状态数据同步。

​ 3. 当@consume装饰的数据变化时:

通过初始渲染的步骤可知,子组件@consume持有@provide的实例。在@consume更新后调用@provide的更新方法,将更新的数值同步回@provide,以此实现@consume向@provide的同步更新。

使用场景

在下面的示例是与后代组件双向同步状态@provide和@consume场景。当分别点击compa和compd组件内button时,reviewvotes 的更改会双向同步在compa和compd中。

@component
struct compd {
  // @consume装饰的变量通过相同的属性名绑定其祖先组件compa内的@provide装饰的变量
  @consume reviewvotes: number;

  build() {
    column() {
      text(`reviewvotes(${this.reviewvotes})`)
      button(`reviewvotes(${this.reviewvotes}), give +1`)
        .onclick(() => this.reviewvotes += 1)
    }
    .width('50%')
  }
}

@component
struct compc {
  build() {
    row({ space: 5 }) {
      compd()
      compd()
    }
  }
}

@component
struct compb {
  build() {
    compc()
  }
}

@entry
@component
struct compa {
  // @provide装饰的变量reviewvotes由入口组件compa提供其后代组件
  @provide reviewvotes: number = 0;

  build() {
    column() {
      button(`reviewvotes(${this.reviewvotes}), give +1`)
        .onclick(() => this.reviewvotes += 1)
      compb()
    }
  }
}

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com