@Provider和@Consumer用于跨组件层级数据双向同步,可以使得开发者不拘泥于组件层级。
@Provider和@Consumer属于状态管理V2装饰器,所以只能在@ComponentV2中才能使用,在@Component中使用会编译报错。
@Provider和@Consumer装饰器从API version 12开始支持。
当前状态管理(V2试用版)仍在逐步开发中,相关功能尚未成熟,建议开发者尝鲜试用。
@Provider,即数据提供方,其所有的子组件都可以通过@Consumer绑定相同的key来获取@Provider提供的数据。
@Consumer,即数据消费方,可以通过绑定同样的key获取其最近父节点的@Provider的数据,当查找不到@Provider的数据时,使用本地默认值。
@Provider和@Consumer装饰数据类型需要一致。
开发者在使用@Provider和@Consumer时要注意:
在状态管理V1版本中,提供跨组件层级双向的装饰器为@Provide和@Consume,当前文档介绍的是状态管理V2装饰器@Provider和@Consumer。虽然两者名字和功能类似,但在特性上还存在一些差异。
如果开发者对状态管理V1中@Provide和@Consume完全不曾了解过,可以直接跳过本节。
能力 | V2装饰器@Provider和@Consumer | V1装饰器@Provide和@Consume |
---|---|---|
@Consume(r) | 允许本地初始化,当找不到@Provider的时候使用本地默认值。 | 禁止本地初始化,当找不到对应的的@Provide时候,会抛出异常。 |
支持类型 | 支持function。 | 不支持function。 |
观察能力 | 仅能观察自身赋值变化,如果要观察嵌套场景,配合@Trace一起使用。 | 观察第一层变化,如果要观察嵌套场景,配合@Observed和@ObjectLink一起使用。 |
alias和属性名 | alias是唯一匹配的key,如果缺省alias,则默认属性名为alias。 | alias和属性名都为key,优先匹配alias,匹配不到可以匹配属性名。 |
@Provide(r) 从父组件初始化 | 禁止。 | 允许。 |
@Provide(r)支持重载 | 默认开启,即@Provider可以重名,@Consumer向上查找最近的@Provider。 | 默认关闭,即在组件树上不允许有同名@Provide。如果需要重载,则需要配置allowOverride。 |
@Provider语法:
@Provider(alias?: string) varName : varType = initValue
@Provider属性装饰器 | 说明 |
---|---|
装饰器参数 | aliasName?: string,别名,缺省时默认为属性名。 |
支持类型 | 自定义组件中成员变量。属性的类型可以为number、string、boolean、class、Array、Date、Map、Set等类型。支持修饰箭头函数。 |
从父组件初始化 | 禁止。 |
本地初始化 | 必须本地初始化。 |
观察能力 | 能力等同于@Trace。变化会同步给对应的@Consumer。 |
@Consumer语法:
@Consumer(alias?: string) varName : varType = initValue
@Consumer属性装饰器 | 说明 |
---|---|
装饰器参数 | aliasName?: string,别名,缺省时默认为属性名,向上查找最近的@Provider。 |
可装饰的变量 | 自定义组件中成员变量。属性的类型可以为number、string、boolean、class、Array、Date、Map、Set等类型。支持修饰箭头函数。 |
从父组件初始化 | 禁止。 |
本地初始化 | 必须本地初始化。 |
观察能力 | 能力等同于@Trace。变化会同步给对应的@Provider。 |
@Provider和@Consumer可接受可选参数aliasName,如果开发者没有配置参数,则使用属性名作为默认值。注意:aliasName是@Provider和@Consumer匹配唯一指定key。
以下三个例子可清楚介绍@Provider和@Consumer在使用aliasName查找关系。
@ComponentV2 struct Parent { @Provider() str: string = 'hello'; // no aliasName, use propertyName "str" as aliasName } @ComponentV2 struct Child { @Consumer('str') str: string = 'world'; // use aliasName 'str' to find // can find in Parent, use Provider value 'hello' }
@ComponentV2 struct Parent { @Provider('alias') str: string = 'hello'; // has alias } @ComponentV2 struct Child { @Consumer('alias') str: string = 'world'; // use aliasName 'alias' to find Provider value 'hello' }
@ComponentV2 struct Parent { @Provider('alias') str: string = 'hello'; // has alias } @ComponentV2 struct Child { @Consumer() str: string = 'world'; // no aliasName, use propertyName "str" as aliasName, cannot find Provider, so use the local value 'world' }
建立双向绑定
@Entry @ComponentV2 struct Parent { @Provider() str: string = 'hello'; build() { Column() { Button(this.str) .onClick(() => { this.str += '0'; }) Child() } } } @ComponentV2 struct Child { @Consumer() str: string = 'world'; build() { Column() { Button(this.str) .onClick(() => { this.str += '0'; }) } } }
未双向绑定
下面的例子中,@Provider和@Consumer由于key值不同,无法建立双向同步关系。
@Entry @ComponentV2 struct Parent { @Provider() str1: string = 'hello'; build() { Column() { Button(this.str1) .onClick(() => { this.str1 += '0'; }) Child() } } } @ComponentV2 struct Child { @Consumer() str: string = 'world'; build() { Column() { Button(this.str) .onClick(() => { this.str += '0'; }) } } }
当需要在父组件中需要给子组件注册回调函数,可以通过@Provider和@Consumer修饰回调方法来解决。
比如拖拽场景,当发生拖拽事件时,如果希望将子组件的拖拽的起始位置信息同步给父组件。如下面的例子。
@Entry @ComponentV2 struct Parent { @Local childX: number = 0; @Local childY: number = 1; @Provider() onDrag: (x: number, y: number) => void = (x: number, y: number) => { console.log(`onDrag event at x=${x} y:${y}`); this.childX = x; this.childY = y; } build() { Column() { Text(`child postion x: ${this.childX}, y: ${this.childY}`) Child() } } } @ComponentV2 struct Child { @Consumer() onDrag: (x: number, y: number) => void = (x: number, y: number) => {}; build() { Button("changed") .draggable(true) .onDragStart((event: DragEvent) => { // 当前预览器上不支持通用拖拽事件 this.onDrag(event.getDisplayX(), event.getDisplayY()); }) } }
@ObservedV2 class User { @Trace name: string; @Trace age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } } const data: User[] = [new User('Json', 10), new User('Eric', 15)]; @Entry @ComponentV2 struct Parent { @Provider('data') users: User[] = data; build() { Column() { Child() Button('age new user') .onClick(() => { this.users.push(new User('Molly', 18)); }) Button('age++') .onClick(() => { this.users[0].age++; }) Button('change name') .onClick(() => { this.users[0].name = 'Shelly'; }) } } } @ComponentV2 struct Child { @Consumer('data') users: User[] = []; build() { Column() { ForEach(this.users, (item: User) => { Column() { Text(`name: ${item.name}`).fontSize(30) Text(`age: ${item.age}`).fontSize(30) Divider() } }) } } }
@Provider可以在组件树上重名,@Consumer会向上查找其最近父节点的@Provider的数据。
@Entry @ComponentV2 struct Parent { @Provider() val: number = 10; build() { Column() { AComp() } } } @ComponentV2 struct AComp { @Provider() val: number = 20; @Consumer("val") val2: number = 0; // 10 build() { Column() { Text(`${this.val2}`) A1Comp() } } } @ComponentV2 struct A1Comp { @Consumer() val: number = 0; // 20 build() { Text(`${this.val}`) } }
@Entry @ComponentV2 struct Parent { @Provider() val: number = 10; build() { Column() { AComp({ val2: this.val }) } } } @ComponentV2 struct AComp { @Consumer() val: number = 0; @Param val2: number = 0; build() { Column() { Text(`AComp @Consumer val: ${this.val}`).fontSize(30).onClick(() => { this.val++; }) Text(`AComp @Param val2: ${this.val2}`).fontSize(30) A1Comp({ val: this.val }) }.border({ width: 2, color: Color.Green }) } } @ComponentV2 struct A1Comp { @Param val: number = 0; build() { Column() { Text(`A1Comp @Param val ${this.val}`).fontSize(30) }.border({ width: 2, color: Color.Pink }) } }
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。
点击领取→【纯血版鸿蒙全套最新学习资料】(安全链接,放心点击)希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取~限时开源!!
鸿蒙(HarmonyOS NEXT)最新学习路线
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。
获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、(南向驱动、嵌入式等)鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。
HarmonyOS Next 最新全套视频教程
《鸿蒙 (OpenHarmony)开发基础到实战手册》
OpenHarmony北向、南向开发环境搭建
《鸿蒙开发基础》
《鸿蒙开发进阶》
《鸿蒙进阶实战》
大厂面试必问面试题
鸿蒙南向开发技术
鸿蒙APP开发必备
请点击→纯血版全套鸿蒙HarmonyOS学习资料
总结
总的来说,华为鸿蒙不再兼容安卓,对程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,才能在这个变革的时代中立于不败之地。