鸿蒙 入门——ArkUI 自定义组件间的“后代“双向同步@Provide和@Consume装饰器小结(五)

news2024/12/24 3:06:27

文章大纲

  • 引言
  • 一、@Provide和@Consume装饰器概述
    • 1、@Provide和@Consume关系的绑定
    • 2、使用规则
    • 3、变量的传递/访问规则
    • 4、支持的观察变化的场景
    • 5、@Provide和@Consume变量的值初始化和更新机制
      • 5.1、初始渲染
      • 5.2、当@Provide装饰的数据变化时:
      • 5.3、当@Consume装饰的数据变化时
  • 三、简单应用
  • 四、利用@Provide 和@Consume 传递回调接口
    • 1、@Provide 定义要传递的回调接口
    • 2、@Consume 定义使用这个回调接口

引言

前面添加链接描述OpenHarmony 入门——ArkUI 自定义组件间的父子双向同步状态装饰器@Link语法(四)介绍了父子组件间的双向同步@Link的使用方法,只能是在单层级上传递,而今天介绍来的这组是可以在多层级之间传递的@Provide和@Consume装饰器。

此处的后代并非传统意义上的后代继承关系,仅仅是代表一种认为约定的关系,所有使用@Provide装饰器的都可以认为是其后代,更贴切些应该是“生产-消费”模型装饰器。

一、@Provide和@Consume装饰器概述

应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。
其中**@Provide装饰的变量是在祖先组件中,即“提供”给后代的状态变量,@Consume装饰的变量是在后代组件中,去“消费(绑定)”祖先组件提供**的变量。

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

  • 后代通过使用**@Consume去获取@Provide提供的变量**,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,前者可以在多层级的父子组件之间传递。

1、@Provide和@Consume关系的绑定

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

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

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

@Provide装饰的变量和@Consume装饰的变量是一对多的关系。不允许在同一个自定义组件内,包括其子组件中声明多个同名或者同别名的@Provide装饰的变量,@Provide的属性名或别名需要唯一且确定,如果声明多个同名或者同别名的@Provide装饰的变量,会发生运行时报错。即先通过@Provide 定义一个所谓的 祖先变量,然后再在其他组件里定义一个@Consume 的 后代变量,那么只要祖先变量值改变时都可以通知到所有绑定了这个后代变量的组件的,完成数据同步,轻松实现跨组件

2、使用规则

@State的规则同样适用于@Provide,不同的是@Provide还作为多层后代的同步源。
在这里插入图片描述

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

在这里插入图片描述
在这里插入图片描述

4、支持的观察变化的场景

  • 数据类型为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()
    }
  }
}

5、@Provide和@Consume变量的值初始化和更新机制

在这里插入图片描述

5.1、初始渲染

  • @Provide装饰的变量会以map的形式,传递给当前@Provide所属组件的所有子组件;
  • 子组件中如果使用@Consume变量,则会在map中查找是否有该变量名/alias(别名)对应的@Provide的变量,如果查找不到,框架会抛出JS ERROR;
  • 在初始化@Consume变量时,和@State/@Link的流程类似,@Consume变量会保存在map中查找到的@Provide变量,并把自己注册给@Provide。

5.2、当@Provide装饰的数据变化时:

  • 通过初始渲染的步骤可知,子组件@Consume已把自己注册给父组件。父组件@Provide变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(@Consume);
  • 通知@Consume更新后,子组件所有依赖@Consume的系统组件(elementId)都会被通知更新。以此实现@Provide对@Consume状态数据同步。

5.3、当@Consume装饰的数据变化时

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

三、简单应用

@Component
struct ConsumeCompA {
  // @Consume装饰的变量通过相同的属性名绑定其祖先组件CompA内的@Provide装饰的变量
  @Consume reviewVotes: number;

  build() {
    Column() {
      Button(`ConsumeCompA @Provide变量+3 后: ${this.reviewVotes}`)
        .onClick(() => this.reviewVotes += 3)
    }
    .width('50%')
  }
}
@Component
struct ConsumeCompC {
  build() {
    Row({ space: 5 }) {
      ConsumeCompA()
      ConsumeCompA()
    }
  }
}
@Component
struct ConsumeCompB {
  build() {
    ConsumeCompC()
  }
}

@Entry
@Component
struct ProvideComp {
  // @Provide装饰的变量reviewVotes由入口组件ProvideComp提供其后代组件
  @Provide reviewVotes: number = 68;
  build() {
    Column() {
      Button(`ProvideComp  @Provide 变量 + 2后 :${this.reviewVotes}`)
        .onClick(() => this.reviewVotes += 2).width('100%')
      Divider().height(20)
      ConsumeCompB()
      Divider().height(20)
      ConsumeCompA().backgroundColor('#ff0000').width('100%')
    }
  }
}

在这里插入图片描述

四、利用@Provide 和@Consume 传递回调接口

1、@Provide 定义要传递的回调接口

@Provide 注解用于提供一个可以在子组件中注入的值,在这里是一个 dialogCallback 对象,包含两个回调函数:confirmCallback 和 cancelCallback。

export interface DialogCallback {
  confirmCallback: Function;
  cancelCallback: Function;
}

@Component
export struct CustomDialogView {
  @Provide dialogCallback: DialogCallback = { confirmCallback: (): void => {}, cancelCallback: () => {} };

  private showDeleteDialog(deleteMessage: Resource, confirmCallback: Function, cancelCallback: Function): void {
    this.dialogCallback = { confirmCallback: confirmCallback, cancelCallback: cancelCallback as Function };
  }
    private showRemoveDialog(removeMessage: Resource, confirmCallback: Function, cancelCallback?: Function): void {
    this.dialogCallback = { confirmCallback: confirmCallback, cancelCallback: cancelCallback as Function };
  }
}

showDeleteDialog 方法用于展示删除对话框,接收一个资源字符串 deleteMessage 和两个回调函数作为参数,设置 dialogMessage 和 dialogCallback 的值。

2、@Consume 定义使用这个回调接口

@Consume 注解用于消费由父组件提供的值,在这里消费的是 dialogCallback。当DeleteDialog 被 CustomDialogView 使用,当需要展示删除确认对话框时,CustomDialogView 将通过 showDeleteDialog 方法来调用 DeleteDialog

@CustomDialog
export struct DeleteDialog {
	@Consume dialogCallback: DialogCallback;
	build() {
	Column() {
		Button()
		.key('DeleteDialogConfirmButton')
		.onClick(() => {
		  this.dialogCallback && this.dialogCallback.confirmCallback();
		})
		}
	  }
}

RemoveDialog

@CustomDialog
export struct RemoveDialog {
  @Consume dialogCallback: DialogCallback;
  build() {
	Column() {
		Button()
		.key('DeleteDialogConfirmButton')
		.onClick(() => {
		  this.dialogCallback && this.dialogCallback.confirmCallback();
		})
		}
	  }
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2240585.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【MySQL从入门到放弃】InnoDB磁盘结构(一)

前言 从MySQL 5.5版本开始默认 使用InnoDB作为引擎,它擅长处理事务,具有自动崩溃恢复的特性,在日常开发中使用非常广泛。 下面是官方的InnoDB引擎架构图,主要分为内存结构和磁盘结构两大部分。 上一篇文章,我们解析了…

C哈的刷题计划之输出数字螺旋矩阵(1)

1、盲听C哈说 都说数据结构与算法是编程的核心,它们两个是内功与心法😀,其它编程工具只是招式,学会了内功与心法,学习新事物(这里特指层出不穷的IT技术)就没有那么难了,实际上&#…

cv::RotatedRect::points误差较大

最后发现不是point的精度问题,float不至于产生这么大误差,是自己代码里缓存了顶点坐标,后面由手动修改了旋转矩形的角度,导致不匹配! 下文可以忽略了-_-! 发现一个天坑,通过高宽和角度构造了一个旋转矩形 …

ThinkServer SR658H V2服务器BMC做raid与装系统

目录 前提准备 一. 给磁盘做raid 二. 安装系统 前提准备 磁盘和系统BMC地址都已经准备好,可正常使用。 例: 设备BMC地址:10.99.240.196 一. 给磁盘做raid 要求: 1. 将两个894G的磁盘做成raid1 2. 将两块14902G的磁盘各自做…

7天用Go从零实现分布式缓存GeeCache(学习)(2)

参考:https://geektutu.com/post/geecache-day2.html // Cache 是一个 LRU 缓存(最近最少使用缓存),它不是并发安全的。 type Cache struct { maxBytes int64 // 缓存的最大字节数 nbytes int64 …

Ajax 与 Vue 框架应用点——随笔谈

老式 在老式的技术中,一个网页通常由前端工程师直接使用 HTML、CSS、JavaScript 编写而成 这种方式的优点很明显:简单粗暴,方便工程师以简单的思维完成工作 当然,缺点也很明显,包括但不限于: 直接原生开发…

鸿蒙动画开发06——打断动画

1、前 言 UI界面除了运行动画之外,还承载着与用户进行实时交互的功能。当用户行为根据意图变化发生改变时,UI界面应做到即时响应。 例如用户在应用启动过程中,上滑退出,那么启动动画应该立即过渡到退出动画,而不应该…

vue2和vue3的区别详解

vue2 VS vue3 对比vue2vue3配置脚手架cmd命令行可视化方式创建脚⼿架组件通信props、$emit、provide、$arrts、EventBus等props、$emit、provide、inject、arrts等数据监听watch,computedwatch,watchEffect,computed双向绑定Object.definePropertyProxyAPI⽣命周期四个阶段befo…

Spring Cloud Eureka 服务注册与发现

Spring Cloud Eureka 服务注册与发现 一、Eureka基础知识概述1.Eureka两个核心组件2.Eureka 服务注册与发现 二、Eureka单机搭建三、Eureka集群搭建四、心跳续约五、Eureka自我保护机制 一、Eureka基础知识概述 1.Eureka两个核心组件 Eureka Server :服务注册中心…

用MVVM设计模式提升WPF开发体验:分层架构与绑定实例解析

MVVM(Model-View-ViewModel)是一种架构模式,广泛应用于现代前端开发,尤其是在微软的WPF(Windows Presentation Foundation)应用程序中。它旨在通过将视图(UI)与业务逻辑(…

飞牛云fnOS本地部署WordPress个人网站并一键发布公网远程访问

文章目录 前言1. Docker下载源设置2. Docker下载WordPress3. Docker部署Mysql数据库4. WordPress 参数设置5. 飞牛云安装Cpolar工具6. 固定Cpolar公网地址7. 修改WordPress配置文件8. 公网域名访问WordPress 前言 本文旨在详细介绍如何在飞牛云NAS上利用Docker部署WordPress&a…

论文笔记 SuDORMRF:EFFICIENT NETWORKS FOR UNIVERSAL AUDIO SOURCE SEPARATION

SUDORMRF: EFFICIENT NETWORKS FOR UNIVERSAL AUDIO SOURCE SEPARATION 人的精神寄托可以是音乐,可以是书籍,可以是运动,可以是工作,可以是山川湖海,唯独不可以是人。 Depthwise Separable Convolution 深度分离卷积&a…

【HarmonyOS】鸿蒙系统在租房项目中的项目实战(一)

从今天开始,博主将开设一门新的专栏用来讲解市面上比较热门的技术 “鸿蒙开发”,对于刚接触这项技术的小伙伴在学习鸿蒙开发之前,有必要先了解一下鸿蒙,从你的角度来讲,你认为什么是鸿蒙呢?它出现的意义又是…

/// ts中的三斜线指令 | 前端

第一次看到注意到这行代码,不知道的还以为是注释呢,查了资料才知道这是typescript中的三斜线指令,那有什么作用呢? 1. 这行代码是TypeScript中的一个三斜线指令(Triple-Slash Directive),用于…

学习日记_20241110_聚类方法(K-Means)

前言 提醒: 文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。 其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展…

SMA-BP基于黏菌算法优化BP神经网络时间序列预测

项目源码获取方式见文章末尾! 600多个深度学习项目资料,快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于CNN-RNN的影像报告生成】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实现…

ssm103宠物领养系统+vue(论文+源码)_kaic

毕业设计(论文) 宠物领养系统的设计与实现 学生姓名: 二级学院: 班级名称: 指导教师: 年 月 日 录 摘 …

Elasticsearch如果集群出现节点故障,我应该如何快速定位问题?

当 Elasticsearch (ES) 集群发生故障时,快速定位问题源头非常重要。Elasticsearch 是一个分布式系统,故障可能由多种原因引起,涉及到硬件、配置、网络、集群本身的健康状况等多个层面。以下是一些定位问题的步骤和工具: 检查集群…

k8s-service、endpoints、pod之间是怎么进行网络互通的

k8s-service、endpoints、pod之间是怎么进行网络互通的 1、service2、endpoints3、service、endpoints、pod通信图4、不同服务pod内部间访问 1、service 在K8S中,Service是一种抽象,定义了一组Pod的逻辑集合和访问这些Pod的策略。首先,我们需…

dbeaver 连接日常是数据库工具类似navicat

官网下载安装包 DBeaver Community | Free Universal Database Tool 登录mysql为例 字体调整 sql 美化,关键字大写 快捷键 执行 ctrlenter 单个语句执行 alt x 执行sql脚本 事务提交,默认自动,可以改成手动 创建数据库 新建表 添加主键 …