android2harmony 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agents/scripts/hmos-precheck/index.mjs +0 -8
- package/agents/self-tester.md +339 -0
- package/dist/index.js +635 -77
- package/dist/index.js.map +4 -4
- package/package.json +37 -29
- package/skills/hmos-incremental-ui-align/README.md +251 -0
- package/skills/hmos-incremental-ui-align/SKILL.md +365 -0
- package/skills/hmos-incremental-ui-align/diff_analysis.md +53 -0
- package/skills/hmos-incremental-ui-align/page_align.md +62 -0
- package/skills/hmos-incremental-ui-align/references/Comparison_Template.md +38 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md +648 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md +2089 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md +1033 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md +1183 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md +576 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md +297 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md +395 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md +903 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md +106 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md +1178 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/MVVM/346/250/241/345/274/217V1.md +911 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +355 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md +11 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/!!/350/257/255/346/263/225/357/274/232/345/217/214/345/220/221/347/273/221/345/256/232.md +206 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Computed/350/243/205/351/245/260/345/231/250/357/274/232/350/256/241/347/256/227/345/261/236/346/200/247.md +373 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Event/350/243/205/351/245/260/345/231/250/357/274/232/350/247/204/350/214/203/347/273/204/344/273/266/350/276/223/345/207/272.md +158 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Local/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/351/203/250/347/212/266/346/200/201.md +750 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Monitor/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/344/277/256/346/224/271/345/274/202/346/255/245/347/233/221/345/220/254.md +1704 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@ObservedV2/350/243/205/351/245/260/345/231/250/345/222/214@Trace/350/243/205/351/245/260/345/231/250/357/274/232/347/261/273/345/261/236/346/200/247/345/217/230/345/214/226/350/247/202/346/265/213.md +1012 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Once/350/243/205/351/245/260/345/231/250/357/274/232/345/210/235/345/247/213/345/214/226/345/220/214/346/255/245/344/270/200/346/254/241.md +164 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Param/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/244/226/351/203/250/350/276/223/345/205/245.md +840 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Provider/350/243/205/351/245/260/345/231/250/345/222/214@Consumer/350/243/205/351/245/260/345/231/250/357/274/232/350/267/250/347/273/204/344/273/266/345/261/202/347/272/247/345/217/214/345/220/221/345/220/214/346/255/245.md +856 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/@Type/350/243/205/351/245/260/345/231/250/357/274/232/346/240/207/350/256/260/347/261/273/345/261/236/346/200/247/347/232/204/347/261/273/345/236/213.md +83 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/AppStorageV2/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200UI/347/212/266/346/200/201/345/255/230/345/202/250.md +294 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/MVVM/346/250/241/345/274/217/357/274/210V2/357/274/211.md +1407 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/PersistenceV2/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md +1220 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2/_/350/214/203/345/274/217/351/200/211/346/213/251/350/257/264/346/230/216.md +47 -0
- package/skills/hmos-incremental-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243V2//347/212/266/346/200/201/347/256/241/347/220/206V1/345/220/221V2/350/277/201/347/247/273/344/270/216/346/267/267/347/224/250/346/214/207/345/257/274.md +840 -0
- package/skills/hmos-incremental-ui-align/references/State_Model_Template.md +74 -0
- package/skills/hmos-incremental-ui-align/references/UI_Analysis_Template.md +34 -0
- package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +2533 -0
- package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-interaction-mapping-reference.md +555 -0
- package/skills/hmos-incremental-ui-align/references/android-to-harmonyOS-ui-layout-mapping-reference.md +117 -0
- package/skills/hmos-incremental-ui-align/scripts/app_feature_verify.ts +999 -0
- package/skills/hmos-incremental-ui-align/scripts/extract_checklist.ts +343 -0
- package/skills/hmos-incremental-ui-align/scripts/navigation-capure.md +76 -0
- package/skills/hmos-incremental-ui-align/scripts/page_capture.ts +977 -0
- package/skills/hmos-incremental-ui-align/scripts/page_capture_burst.ts +188 -0
- package/skills/hmos-spec-generate/SKILL.md +1 -1
- package/tools/autotest/deps/autotest-agent-0.1.1.tgz +0 -0
- package/tools/autotest/engine/batch-launcher.ts +326 -0
- package/tools/autotest/engine/report-tool.ts +773 -0
- package/tools/autotest/engine/self-test-runner.ts +1024 -0
- package/tools/autotest/engine/testcases-tool.ts +246 -0
- package/tools/autotest/resolve-metadata-tool.ts +143 -0
- package/tools/autotest/runner/logger.ts +45 -0
- package/tools/autotest/runner/process-utils.ts +41 -0
- package/tools/autotest/validate.ts +115 -0
|
@@ -0,0 +1,856 @@
|
|
|
1
|
+
@Provider和@Consumer用于跨组件层级数据双向同步,可以使得开发者不用拘泥于组件层级。
|
|
2
|
+
|
|
3
|
+
@Provider和@Consumer属于状态管理V2装饰器,所以只能在@ComponentV2中才能使用,在@Component中使用会编译报错。
|
|
4
|
+
|
|
5
|
+
@Provider和@Consumer提供了跨组件层级数据双向同步的能力。在阅读本文档前,建议提前阅读:[@ComponentV2](../../../../学习UI范式基本语法/自定义组件/创建自定义组件/arkts-create-custom-components.md#componentv2)。常见问题请参考[组件内状态变量常见问题](../../../状态管理常见问题/组件内状态管理常见问题/arkts-state-management-faq-inner-component.md)。
|
|
6
|
+
|
|
7
|
+
说明
|
|
8
|
+
|
|
9
|
+
@Provider和@Consumer装饰器从API version 12开始支持。
|
|
10
|
+
|
|
11
|
+
从API version 12开始,@Provider和@Consumer装饰器支持在元服务中使用。
|
|
12
|
+
|
|
13
|
+
从API version 23开始,通过配置[BuilderNode](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/arkui/BuilderNode/js-apis-arkui-buildernode.md>)的[BuildOptions](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/arkui/BuilderNode/js-apis-arkui-buildernode.md#buildoptions12>)参数enableProvideConsumeCrossing为true,使得@Provider和@Consumer支持跨[BuilderNode](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/arkui/BuilderNode/js-apis-arkui-buildernode.md>)双向同步。在BuilderNode挂载到自定义组件节点树之后,@Consumer会重新获取最近的@Provider数据,与之建立双向同步关系。具体可见[@Consumer在跨BuilderNode场景下和@Provider建立双向同步](arkts-new-provider-and-consumer.md#consumer在跨buildernode场景下和provider建立双向同步过程)。
|
|
14
|
+
|
|
15
|
+
从API version 23开始,@Provider和@Consumer装饰器支持在ArkTS卡片中使用。
|
|
16
|
+
|
|
17
|
+
## 概述
|
|
18
|
+
|
|
19
|
+
@Provider,即数据提供方,其所有的子组件都可以通过@Consumer绑定相同的key来获取@Provider提供的数据。
|
|
20
|
+
|
|
21
|
+
@Consumer,即数据消费方,可以通过绑定同样的key获取其最近父节点的@Provider的数据,当查找不到@Provider的数据时,使用本地默认值。图示如下。
|
|
22
|
+
|
|
23
|
+

|
|
24
|
+
|
|
25
|
+
@Provider和@Consumer装饰的数据类型需要一致。
|
|
26
|
+
|
|
27
|
+
开发者在使用@Provider和@Consumer时要注意:
|
|
28
|
+
|
|
29
|
+
* @Provider和@Consumer强依赖自定义组件层级,@Consumer会因为所在组件的父组件不同,而被初始化为不同的值。
|
|
30
|
+
* @Provider和@Consumer相当于把组件粘合在一起了,从组件独立角度考虑,应减少使用@Provider和@Consumer。
|
|
31
|
+
|
|
32
|
+
## @Provider和@Consumer vs @Provide和@Consume能力对比
|
|
33
|
+
|
|
34
|
+
在状态管理V1版本中,提供跨组件层级双向的装饰器为[@Provide和@Consume](../../../状态管理(V1)/管理组件拥有的状态/@Provide装饰器和@Consume装饰器:与后代组件双向同步/arkts-provide-and-consume.md),当前文档介绍的是状态管理V2装饰器@Provider和@Consumer。虽然两者名字和功能类似,但在特性上还存在一些差异。
|
|
35
|
+
|
|
36
|
+
如果开发者不了解状态管理V1中的@Provide和@Consume,可以直接跳过本节。
|
|
37
|
+
|
|
38
|
+
| 能力 | V2装饰器@Provider和@Consumer | V1装饰器@Provide和@Consume |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| @Consume(r) | 必须本地初始化,当找不到@Provider时使用本地默认值。 | API version 20以前,@Consume禁止本地初始化,当找不到对应@Provide的时候,会抛出异常;从API version 20开始,@Consume支持设置默认值,如果没有设置默认值,且找不到对应@Provide时,会抛出异常。 |
|
|
41
|
+
| 支持类型 | 支持function。 | 不支持function。 |
|
|
42
|
+
| 观察能力 | 仅能观察自身赋值变化,如果要观察嵌套场景,配合[@Trace](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace)一起使用。 | 观察第一层变化,如果要观察嵌套场景,配合[@Observed和@ObjectLink](../../../状态管理(V1)/管理组件拥有的状态/@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化/arkts-observed-and-objectlink.md)一起使用。 |
|
|
43
|
+
| alias和属性名 | alias是唯一匹配的key,缺省时默认属性名为alias。 | alias和属性名都为key,优先匹配alias,匹配不到可以匹配属性名。 |
|
|
44
|
+
| @Provide(r) 从父组件初始化 | 不允许。 | 允许。 |
|
|
45
|
+
| @Provide(r)支持重载 | 默认开启,即@Provider可以重名,@Consumer向上查找最近的@Provider。 | 默认关闭,即在组件树上不允许有同名@Provide。如果需要重载,则需要配置allowOverride。 |
|
|
46
|
+
|
|
47
|
+
## 装饰器说明
|
|
48
|
+
|
|
49
|
+
### 基本规则
|
|
50
|
+
|
|
51
|
+
@Provider语法:
|
|
52
|
+
|
|
53
|
+
@Provider(aliasName?: string) varName : varType = initValue
|
|
54
|
+
|
|
55
|
+
| @Provider属性装饰器 | 说明 |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| 装饰器参数 | aliasName?: string,别名,缺省时默认为属性名。 |
|
|
58
|
+
| 支持类型 | 自定义组件中成员变量。属性的类型可以为number、string、boolean、class、[Array](arkts-new-provider-and-consumer.md#装饰array类型变量)、[Date](arkts-new-provider-and-consumer.md#装饰date类型变量)、[Map](arkts-new-provider-and-consumer.md#装饰map类型变量)、[Set](arkts-new-provider-and-consumer.md#装饰set类型变量)等类型。支持装饰[箭头函数](arkts-new-provider-and-consumer.md#provider和consumer装饰回调事件用于组件之间完成行为抽象)。 |
|
|
59
|
+
| 从父组件初始化 | 禁止。 |
|
|
60
|
+
| 本地初始化 | 必须本地初始化。 |
|
|
61
|
+
| 观察能力 | 能力等同于@Trace。变化会同步给对应的@Consumer。 |
|
|
62
|
+
|
|
63
|
+
@Consumer语法:
|
|
64
|
+
|
|
65
|
+
@Consumer(aliasName?: string) varName : varType = initValue
|
|
66
|
+
|
|
67
|
+
| @Consumer属性装饰器 | 说明 |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| 装饰器参数 | aliasName?: string,别名,缺省时默认为属性名,向上查找最近的@Provider。 |
|
|
70
|
+
| 可装饰的变量 | 自定义组件中成员变量。属性的类型可以为number、string、boolean、class、Array、Date、Map、Set等类型。支持装饰箭头函数。 |
|
|
71
|
+
| 从父组件初始化 | 禁止。 |
|
|
72
|
+
| 本地初始化 | 必须本地初始化。 |
|
|
73
|
+
| 观察能力 | 能力等同于@Trace。变化会同步给对应的@Provider。 |
|
|
74
|
+
|
|
75
|
+
### aliasName和属性名
|
|
76
|
+
|
|
77
|
+
@Provider和@Consumer接受可选参数aliasName,没有配置参数时,使用属性名作为默认的aliasName。
|
|
78
|
+
|
|
79
|
+
说明
|
|
80
|
+
|
|
81
|
+
aliasName是用于@Provider和@Consumer进行匹配的唯一指定key。
|
|
82
|
+
|
|
83
|
+
以下三个例子可清楚介绍@Provider和@Consumer如何使用aliasName进行查找匹配。
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
1. @ComponentV2
|
|
87
|
+
2. struct Parent {
|
|
88
|
+
3. // 未定义aliasName, 使用属性名'str'作为aliasName
|
|
89
|
+
4. @Provider() str: string = 'hello';
|
|
90
|
+
5. }
|
|
91
|
+
|
|
92
|
+
7. @ComponentV2
|
|
93
|
+
8. struct Child {
|
|
94
|
+
9. // 定义aliasName为'str',使用aliasName去寻找
|
|
95
|
+
10. // 能够在Parent组件上找到, 使用@Provider的值'hello'
|
|
96
|
+
11. @Consumer('str') str: string = 'world';
|
|
97
|
+
12. }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
1. @ComponentV2
|
|
102
|
+
2. struct Parent {
|
|
103
|
+
3. // 定义aliasName为'alias'
|
|
104
|
+
4. @Provider('alias') str: string = 'hello';
|
|
105
|
+
5. }
|
|
106
|
+
|
|
107
|
+
7. @ComponentV2
|
|
108
|
+
8. struct Child {
|
|
109
|
+
9. // 定义aliasName为 'alias',找到@Provider并获得值'hello'
|
|
110
|
+
10. @Consumer('alias') str: string = 'world';
|
|
111
|
+
11. }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
1. @ComponentV2
|
|
116
|
+
2. struct Parent {
|
|
117
|
+
3. // 定义aliasName为'alias'
|
|
118
|
+
4. @Provider('alias') str: string = 'hello';
|
|
119
|
+
5. }
|
|
120
|
+
|
|
121
|
+
7. @ComponentV2
|
|
122
|
+
8. struct Child {
|
|
123
|
+
9. // 未定义aliasName,使用属性名'str'作为aliasName
|
|
124
|
+
10. // 没有找到对应的@Provider,使用本地值'world'
|
|
125
|
+
11. @Consumer() str: string = 'world';
|
|
126
|
+
12. }
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## 变量传递
|
|
130
|
+
|
|
131
|
+
| 传递规则 | 说明 |
|
|
132
|
+
| --- | --- |
|
|
133
|
+
| 从父组件初始化 | @Provider和@Consumer装饰的变量仅允许本地初始化,不允许从外部传入初始化。 |
|
|
134
|
+
| 初始化子组件 | @Provider和@Consumer装饰的变量可以初始化子组件中@Param装饰的变量。 |
|
|
135
|
+
|
|
136
|
+
## 使用限制
|
|
137
|
+
|
|
138
|
+
1. @Provider和@Consumer为自定义组件的属性装饰器,只能装饰自定义组件内的属性,不能装饰class的属性。
|
|
139
|
+
2. @Provider和@Consumer为状态管理V2装饰器,只能在@ComponentV2中使用,不能在@Component中使用。
|
|
140
|
+
3. @Provider和@Consumer只支持本地初始化,不支持外部传入初始化。
|
|
141
|
+
|
|
142
|
+
## 使用场景
|
|
143
|
+
|
|
144
|
+
### @Provider和@Consumer双向同步
|
|
145
|
+
|
|
146
|
+
**建立双向绑定**
|
|
147
|
+
|
|
148
|
+
1. 自定义组件Parent和Child初始化:
|
|
149
|
+
* Child中@Consumer() str: string = 'world'向上查找,查找到Parent中声明的@Provider() str: string = 'hello'。
|
|
150
|
+
* @Consumer() str: string = 'world'初始化为其查找到的@Provider的值,即'hello'。
|
|
151
|
+
* 两者建立双向同步关系。
|
|
152
|
+
2. 点击Parent中的按钮,改变@Provider装饰的str,通知其对应的@Consumer,对应UI刷新。
|
|
153
|
+
3. 点击Child中的按钮,改变@Consumer装饰的str,通知其对应的@Provider,对应UI刷新。
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
1. @Entry
|
|
157
|
+
2. @ComponentV2
|
|
158
|
+
3. struct Parent {
|
|
159
|
+
4. @Provider() str: string = 'hello';
|
|
160
|
+
|
|
161
|
+
6. build() {
|
|
162
|
+
7. Column() {
|
|
163
|
+
8. Button(this.str)
|
|
164
|
+
9. .onClick(() => {
|
|
165
|
+
10. this.str += '0';
|
|
166
|
+
11. })
|
|
167
|
+
12. Child()
|
|
168
|
+
13. }
|
|
169
|
+
14. }
|
|
170
|
+
15. }
|
|
171
|
+
|
|
172
|
+
17. @ComponentV2
|
|
173
|
+
18. struct Child {
|
|
174
|
+
19. // @Consumer装饰的属性str和Parent组件中@Provider装饰的属性str名称相同,因此建立了双向绑定关系
|
|
175
|
+
20. @Consumer() str: string = 'world';
|
|
176
|
+
|
|
177
|
+
22. build() {
|
|
178
|
+
23. Column() {
|
|
179
|
+
24. Button(this.str)
|
|
180
|
+
25. .onClick(() => {
|
|
181
|
+
26. this.str += '0';
|
|
182
|
+
27. })
|
|
183
|
+
28. }
|
|
184
|
+
29. }
|
|
185
|
+
30. }
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
[TwowayBinding.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/TwowayBinding.ets#L16-L47)
|
|
189
|
+
|
|
190
|
+
**未建立双向绑定**
|
|
191
|
+
|
|
192
|
+
下面的例子中,@Provider和@Consumer由于aliasName值不同,无法建立双向同步关系。
|
|
193
|
+
|
|
194
|
+
1. 自定义组件Parent和Child初始化:
|
|
195
|
+
* Child中@Consumer() str: string = 'world'向上查找,未查找到其数据提供方@Provider。
|
|
196
|
+
* @Consumer() str: string = 'world'使用其本地默认值为'world'。
|
|
197
|
+
* 两者未建立双向同步关系。
|
|
198
|
+
2. 点击Parent中的按钮,改变@Provider装饰的str1,仅刷新@Provider关联的Button组件。
|
|
199
|
+
3. 点击Child中的按钮,改变@Consumer装饰的str,仅刷新@Consumer关联的Button组件。
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
1. @Entry
|
|
203
|
+
2. @ComponentV2
|
|
204
|
+
3. struct Parent {
|
|
205
|
+
4. @Provider() str1: string = 'hello';
|
|
206
|
+
|
|
207
|
+
6. build() {
|
|
208
|
+
7. Column() {
|
|
209
|
+
8. Button(this.str1)
|
|
210
|
+
9. .onClick(() => {
|
|
211
|
+
10. this.str1 += '0';
|
|
212
|
+
11. })
|
|
213
|
+
12. Child()
|
|
214
|
+
13. }
|
|
215
|
+
14. }
|
|
216
|
+
15. }
|
|
217
|
+
|
|
218
|
+
17. @ComponentV2
|
|
219
|
+
18. struct Child {
|
|
220
|
+
19. // @Consumer装饰的属性str和Parent组件中@Provider装饰的属性str1名称不同,无法建立双向绑定关系
|
|
221
|
+
20. @Consumer() str: string = 'world';
|
|
222
|
+
|
|
223
|
+
22. build() {
|
|
224
|
+
23. Column() {
|
|
225
|
+
24. Button(this.str)
|
|
226
|
+
25. .onClick(() => {
|
|
227
|
+
26. this.str += '0';
|
|
228
|
+
27. })
|
|
229
|
+
28. }
|
|
230
|
+
29. }
|
|
231
|
+
30. }
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
[NoTwowayBinding.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/NoTwowayBinding.ets#L16-L47)
|
|
235
|
+
|
|
236
|
+
### 装饰Array类型变量
|
|
237
|
+
|
|
238
|
+
当装饰的对象是Array时,可以观察到Array整体的赋值,同时可以通过调用Array的接口push, pop, shift, unshift, splice, copyWithin, fill, reverse, sort更新Array中的数据。
|
|
239
|
+
|
|
240
|
+
```
|
|
241
|
+
1. @Entry
|
|
242
|
+
2. @ComponentV2
|
|
243
|
+
3. struct Parent {
|
|
244
|
+
4. @Provider() count: number[] = [1, 2, 3];
|
|
245
|
+
|
|
246
|
+
6. build() {
|
|
247
|
+
7. Row() {
|
|
248
|
+
8. Column() {
|
|
249
|
+
9. ForEach(this.count, (item: number) => {
|
|
250
|
+
10. Text(`parent: ${item}`).fontSize(30)
|
|
251
|
+
11. Divider()
|
|
252
|
+
12. })
|
|
253
|
+
13. // count被@Provider装饰,可以被观察到Array整体的赋值以及调用Array接口带来的变化
|
|
254
|
+
14. Button('push').onClick(() => {
|
|
255
|
+
15. this.count.push(111);
|
|
256
|
+
16. })
|
|
257
|
+
17. Button('reverse').onClick(() => {
|
|
258
|
+
18. this.count.reverse();
|
|
259
|
+
19. })
|
|
260
|
+
20. Button('fill').onClick(() => {
|
|
261
|
+
21. this.count.fill(6);
|
|
262
|
+
22. })
|
|
263
|
+
23. Child()
|
|
264
|
+
24. }
|
|
265
|
+
25. .width('100%')
|
|
266
|
+
26. }
|
|
267
|
+
27. .height('100%')
|
|
268
|
+
28. }
|
|
269
|
+
29. }
|
|
270
|
+
|
|
271
|
+
31. @ComponentV2
|
|
272
|
+
32. struct Child {
|
|
273
|
+
33. @Consumer() count: number[] = [9, 8, 7];
|
|
274
|
+
|
|
275
|
+
35. build() {
|
|
276
|
+
36. Column() {
|
|
277
|
+
37. ForEach(this.count, (item: number) => {
|
|
278
|
+
38. Text(`child: ${item}`).fontSize(30)
|
|
279
|
+
39. Divider()
|
|
280
|
+
40. })
|
|
281
|
+
41. // count被@Consumer装饰,可以被观察到Array整体的赋值以及调用Array接口带来的变化
|
|
282
|
+
42. Button('push').onClick(() => {
|
|
283
|
+
43. this.count.push(222);
|
|
284
|
+
44. })
|
|
285
|
+
45. Button('reverse').onClick(() => {
|
|
286
|
+
46. this.count.reverse();
|
|
287
|
+
47. })
|
|
288
|
+
48. Button('fill').onClick(() => {
|
|
289
|
+
49. this.count.fill(8);
|
|
290
|
+
50. })
|
|
291
|
+
51. }
|
|
292
|
+
52. .width('100%')
|
|
293
|
+
53. }
|
|
294
|
+
54. }
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
[DecorativeArray.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeArray.ets#L16-L69)
|
|
298
|
+
|
|
299
|
+
### 装饰Date类型变量
|
|
300
|
+
|
|
301
|
+
当装饰Date类型变量时,可以观察到数据源对Date整体的赋值,以及调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds带来的变化。
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
1. @Entry
|
|
305
|
+
2. @ComponentV2
|
|
306
|
+
3. struct Parent {
|
|
307
|
+
4. @Provider() selectedDate: Date = new Date('2021-08-08');
|
|
308
|
+
|
|
309
|
+
6. build() {
|
|
310
|
+
7. Column() {
|
|
311
|
+
8. Text(`parent: ${this.selectedDate}`)
|
|
312
|
+
9. // selectedDate被@Provider装饰,可以被观察到Date整体的赋值以及调用Date接口带来的变化
|
|
313
|
+
10. Button('update the new date')
|
|
314
|
+
11. .onClick(() => {
|
|
315
|
+
12. this.selectedDate = new Date('2023-07-07');
|
|
316
|
+
13. })
|
|
317
|
+
14. Button('increase the year by 1')
|
|
318
|
+
15. .onClick(() => {
|
|
319
|
+
16. this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1);
|
|
320
|
+
17. })
|
|
321
|
+
18. Button('increase the month by 1')
|
|
322
|
+
19. .onClick(() => {
|
|
323
|
+
20. this.selectedDate.setMonth(this.selectedDate.getMonth() + 1);
|
|
324
|
+
21. })
|
|
325
|
+
22. Button('increase the day by 1')
|
|
326
|
+
23. .onClick(() => {
|
|
327
|
+
24. this.selectedDate.setDate(this.selectedDate.getDate() + 1);
|
|
328
|
+
25. })
|
|
329
|
+
26. Child()
|
|
330
|
+
27. }
|
|
331
|
+
28. }
|
|
332
|
+
29. }
|
|
333
|
+
|
|
334
|
+
31. @ComponentV2
|
|
335
|
+
32. struct Child {
|
|
336
|
+
33. @Consumer() selectedDate: Date = new Date('2022-07-07');
|
|
337
|
+
|
|
338
|
+
35. build() {
|
|
339
|
+
36. Column() {
|
|
340
|
+
37. Text(`child: ${this.selectedDate}`)
|
|
341
|
+
38. // selectedDate被@Consumer装饰,可以被观察到Date整体的赋值以及调用Date接口带来的变化
|
|
342
|
+
39. Button('update the new date')
|
|
343
|
+
40. .onClick(() => {
|
|
344
|
+
41. this.selectedDate = new Date('2025-01-01');
|
|
345
|
+
42. })
|
|
346
|
+
43. Button('increase the year by 1')
|
|
347
|
+
44. .onClick(() => {
|
|
348
|
+
45. this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1);
|
|
349
|
+
46. })
|
|
350
|
+
47. Button('increase the month by 1')
|
|
351
|
+
48. .onClick(() => {
|
|
352
|
+
49. this.selectedDate.setMonth(this.selectedDate.getMonth() + 1);
|
|
353
|
+
50. })
|
|
354
|
+
51. Button('increase the day by 1')
|
|
355
|
+
52. .onClick(() => {
|
|
356
|
+
53. this.selectedDate.setDate(this.selectedDate.getDate() + 1);
|
|
357
|
+
54. })
|
|
358
|
+
55. }
|
|
359
|
+
56. }
|
|
360
|
+
57. }
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
[DecorativeDate.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeDate.ets#L16-L72)
|
|
364
|
+
|
|
365
|
+
### 装饰Map类型变量
|
|
366
|
+
|
|
367
|
+
当装饰Map类型变量时,可以观察到数据源对Map整体的赋值,以及调用Map的接口set, clear, delete带来的变化。
|
|
368
|
+
|
|
369
|
+
```
|
|
370
|
+
1. @Entry
|
|
371
|
+
2. @ComponentV2
|
|
372
|
+
3. struct Parent {
|
|
373
|
+
4. @Provider() message: Map<number, string> = new Map([[0, 'a'], [1, 'b'], [3, 'c']]);
|
|
374
|
+
|
|
375
|
+
6. build() {
|
|
376
|
+
7. Column() {
|
|
377
|
+
8. Text('Parent').fontSize(30)
|
|
378
|
+
9. ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
|
|
379
|
+
10. Text(`${item[0]}`).fontSize(30)
|
|
380
|
+
11. Text(`${item[1]}`).fontSize(30)
|
|
381
|
+
12. Divider()
|
|
382
|
+
13. })
|
|
383
|
+
14. // message被@Provider装饰,可以被观察到Map整体的赋值以及调用Map接口带来的变化
|
|
384
|
+
15. Button('init map').onClick(() => {
|
|
385
|
+
16. this.message = new Map([[0, 'aa'], [1, 'bb'], [3, 'cc']]);
|
|
386
|
+
17. })
|
|
387
|
+
18. Button('set new one').onClick(() => {
|
|
388
|
+
19. this.message.set(4, 'd');
|
|
389
|
+
20. })
|
|
390
|
+
21. Button('clear').onClick(() => {
|
|
391
|
+
22. this.message.clear();
|
|
392
|
+
23. })
|
|
393
|
+
24. Button('replace the first one').onClick(() => {
|
|
394
|
+
25. this.message.set(0, 'a~');
|
|
395
|
+
26. })
|
|
396
|
+
27. Button('delete the first one').onClick(() => {
|
|
397
|
+
28. this.message.delete(0);
|
|
398
|
+
29. })
|
|
399
|
+
30. Child()
|
|
400
|
+
31. }
|
|
401
|
+
32. }
|
|
402
|
+
33. }
|
|
403
|
+
|
|
404
|
+
35. @ComponentV2
|
|
405
|
+
36. struct Child {
|
|
406
|
+
37. @Consumer() message: Map<number, string> = new Map([[0, 'd'], [1, 'e'], [3, 'f']]);
|
|
407
|
+
|
|
408
|
+
39. build() {
|
|
409
|
+
40. Column() {
|
|
410
|
+
41. Text('Child').fontSize(30)
|
|
411
|
+
42. ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
|
|
412
|
+
43. Text(`${item[0]}`).fontSize(30)
|
|
413
|
+
44. Text(`${item[1]}`).fontSize(30)
|
|
414
|
+
45. Divider()
|
|
415
|
+
46. })
|
|
416
|
+
47. // message被@Consumer装饰,可以被观察到Map整体的赋值以及调用Map接口带来的变化
|
|
417
|
+
48. Button('init map').onClick(() => {
|
|
418
|
+
49. this.message = new Map([[0, 'dd'], [1, 'ee'], [3, 'ff']]);
|
|
419
|
+
50. })
|
|
420
|
+
51. Button('set new one').onClick(() => {
|
|
421
|
+
52. this.message.set(4, 'g');
|
|
422
|
+
53. })
|
|
423
|
+
54. Button('clear').onClick(() => {
|
|
424
|
+
55. this.message.clear();
|
|
425
|
+
56. })
|
|
426
|
+
57. Button('replace the first one').onClick(() => {
|
|
427
|
+
58. this.message.set(0, 'a*');
|
|
428
|
+
59. })
|
|
429
|
+
60. Button('delete the first one').onClick(() => {
|
|
430
|
+
61. this.message.delete(0);
|
|
431
|
+
62. })
|
|
432
|
+
63. }
|
|
433
|
+
64. }
|
|
434
|
+
65. }
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
[DecorativeMap.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeMap.ets#L16-L80)
|
|
438
|
+
|
|
439
|
+
### 装饰Set类型变量
|
|
440
|
+
|
|
441
|
+
当装饰Set类型变量时,可以观察到数据源对Set整体的赋值,以及调用Set的接口 add, clear, delete带来的变化。
|
|
442
|
+
|
|
443
|
+
```
|
|
444
|
+
1. @Entry
|
|
445
|
+
2. @ComponentV2
|
|
446
|
+
3. struct Parent {
|
|
447
|
+
4. @Provider() message: Set<number> = new Set([1, 2, 3, 4]);
|
|
448
|
+
|
|
449
|
+
6. build() {
|
|
450
|
+
7. Column() {
|
|
451
|
+
8. Text('Parent').fontSize(30)
|
|
452
|
+
9. ForEach(Array.from(this.message.entries()), (item: [number, number]) => {
|
|
453
|
+
10. Text(`${item[0]}`).fontSize(30)
|
|
454
|
+
11. Divider()
|
|
455
|
+
12. })
|
|
456
|
+
13. // message被@Provider装饰,可以被观察到Set整体的赋值以及调用Set接口带来的变化
|
|
457
|
+
14. Button('init set').onClick(() => {
|
|
458
|
+
15. this.message = new Set([1, 2, 3, 4]);
|
|
459
|
+
16. })
|
|
460
|
+
17. Button('set new one').onClick(() => {
|
|
461
|
+
18. this.message.add(5);
|
|
462
|
+
19. })
|
|
463
|
+
20. Button('clear').onClick(() => {
|
|
464
|
+
21. this.message.clear();
|
|
465
|
+
22. })
|
|
466
|
+
23. Button('delete the first one').onClick(() => {
|
|
467
|
+
24. this.message.delete(1);
|
|
468
|
+
25. })
|
|
469
|
+
26. Child()
|
|
470
|
+
27. }
|
|
471
|
+
28. }
|
|
472
|
+
29. }
|
|
473
|
+
|
|
474
|
+
31. @ComponentV2
|
|
475
|
+
32. struct Child {
|
|
476
|
+
33. @Consumer() message: Set<number> = new Set([1, 2, 3, 4, 5, 6]);
|
|
477
|
+
|
|
478
|
+
35. build() {
|
|
479
|
+
36. Column() {
|
|
480
|
+
37. Text('Child').fontSize(30)
|
|
481
|
+
38. ForEach(Array.from(this.message.entries()), (item: [number, number]) => {
|
|
482
|
+
39. Text(`${item[0]}`).fontSize(30)
|
|
483
|
+
40. Divider()
|
|
484
|
+
41. })
|
|
485
|
+
42. // message被@Consumer装饰,可以被观察到Set整体的赋值以及调用Set接口带来的变化
|
|
486
|
+
43. Button('init set').onClick(() => {
|
|
487
|
+
44. this.message = new Set([1, 2, 3, 4, 5, 6]);
|
|
488
|
+
45. })
|
|
489
|
+
46. Button('set new one').onClick(() => {
|
|
490
|
+
47. this.message.add(7);
|
|
491
|
+
48. })
|
|
492
|
+
49. Button('clear').onClick(() => {
|
|
493
|
+
50. this.message.clear();
|
|
494
|
+
51. })
|
|
495
|
+
52. Button('delete the first one').onClick(() => {
|
|
496
|
+
53. this.message.delete(1);
|
|
497
|
+
54. })
|
|
498
|
+
55. }
|
|
499
|
+
56. }
|
|
500
|
+
57. }
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
[DecorativeSet.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeSet.ets#L16-L72)
|
|
504
|
+
|
|
505
|
+
### @Provider和@Consumer装饰回调事件用于组件之间完成行为抽象
|
|
506
|
+
|
|
507
|
+
当需要在父组件中向子组件注册回调函数时,可以使用@Provider和@Consumer装饰回调方法来实现。
|
|
508
|
+
|
|
509
|
+
在拖拽场景中,若需将子组件的拖拽起始位置信息同步给父组件,可参考以下示例。
|
|
510
|
+
|
|
511
|
+
```
|
|
512
|
+
1. @Entry
|
|
513
|
+
2. @ComponentV2
|
|
514
|
+
3. struct Parent {
|
|
515
|
+
4. @Local childX: number = 0;
|
|
516
|
+
5. @Local childY: number = 1;
|
|
517
|
+
6. @Provider() onDrag: (x: number, y: number) => void = (x: number, y: number) => {
|
|
518
|
+
7. console.info(`onDrag event at x=${x} y:${y}`);
|
|
519
|
+
8. this.childX = x;
|
|
520
|
+
9. this.childY = y;
|
|
521
|
+
10. }
|
|
522
|
+
|
|
523
|
+
12. build() {
|
|
524
|
+
13. Column() {
|
|
525
|
+
14. Text(`child position x: ${this.childX}, y: ${this.childY}`)
|
|
526
|
+
15. Child()
|
|
527
|
+
16. }
|
|
528
|
+
17. }
|
|
529
|
+
18. }
|
|
530
|
+
|
|
531
|
+
20. @ComponentV2
|
|
532
|
+
21. struct Child {
|
|
533
|
+
22. @Consumer() onDrag: (x: number, y: number) => void = (x: number, y: number) => {};
|
|
534
|
+
|
|
535
|
+
24. build() {
|
|
536
|
+
25. Button('changed')
|
|
537
|
+
26. .draggable(true)
|
|
538
|
+
27. .onDragStart((event: DragEvent) => {
|
|
539
|
+
28. // 当前预览器上不支持通用拖拽事件
|
|
540
|
+
29. this.onDrag(event.getDisplayX(), event.getDisplayY());
|
|
541
|
+
30. })
|
|
542
|
+
31. }
|
|
543
|
+
32. }
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
[DragDrop.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DragDrop.ets#L16-L49)
|
|
547
|
+
|
|
548
|
+
### @Provider和@Consumer装饰复杂类型,配合@Trace一起使用
|
|
549
|
+
|
|
550
|
+
1. @Provider和@Consumer只能观察到数据本身的变化。如果需要观察其装饰的复杂数据类型的属性变化,可以配合@Trace一起使用,也可以使用[makeObserved](../../../辅助接口/makeObserved接口:将非观察数据变为可观察数据/arkts-new-makeobserved.md)将非可观察数据变为可观察数据。
|
|
551
|
+
2. 装饰内置类型:Array、Map、Set、Date时,可以观察到某些API的变化,观察能力同[@Trace](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-new-observedv2-and-trace#观察变化)。
|
|
552
|
+
|
|
553
|
+
```
|
|
554
|
+
1. @ObservedV2
|
|
555
|
+
2. class User {
|
|
556
|
+
3. // 复杂数据类型的属性被@Trace装饰,可以被观察到属性变化
|
|
557
|
+
4. @Trace public name: string;
|
|
558
|
+
5. @Trace public age: number;
|
|
559
|
+
|
|
560
|
+
7. constructor(name: string, age: number) {
|
|
561
|
+
8. this.name = name;
|
|
562
|
+
9. this.age = age;
|
|
563
|
+
10. }
|
|
564
|
+
11. }
|
|
565
|
+
12. const data: User[] = [new User('Json', 10), new User('Eric', 15)];
|
|
566
|
+
13. @Entry
|
|
567
|
+
14. @ComponentV2
|
|
568
|
+
15. struct Parent {
|
|
569
|
+
16. @Provider('data') users: User[] = data;
|
|
570
|
+
|
|
571
|
+
18. build() {
|
|
572
|
+
19. Column() {
|
|
573
|
+
20. Child()
|
|
574
|
+
21. Button('add new user')
|
|
575
|
+
22. .onClick(() => {
|
|
576
|
+
23. this.users.push(new User('Molly', 18));
|
|
577
|
+
24. })
|
|
578
|
+
25. Button('age++')
|
|
579
|
+
26. .onClick(() => {
|
|
580
|
+
27. this.users[0].age++;
|
|
581
|
+
28. })
|
|
582
|
+
29. Button('change name')
|
|
583
|
+
30. .onClick(() => {
|
|
584
|
+
31. this.users[0].name = 'Shelly';
|
|
585
|
+
32. })
|
|
586
|
+
33. }
|
|
587
|
+
34. }
|
|
588
|
+
35. }
|
|
589
|
+
|
|
590
|
+
37. @ComponentV2
|
|
591
|
+
38. struct Child {
|
|
592
|
+
39. @Consumer('data') users: User[] = [];
|
|
593
|
+
|
|
594
|
+
41. build() {
|
|
595
|
+
42. Column() {
|
|
596
|
+
43. ForEach(this.users, (item: User) => {
|
|
597
|
+
44. Column() {
|
|
598
|
+
45. Text(`name: ${item.name}`).fontSize(30)
|
|
599
|
+
46. Text(`age: ${item.age}`).fontSize(30)
|
|
600
|
+
47. Divider()
|
|
601
|
+
48. }
|
|
602
|
+
49. })
|
|
603
|
+
50. }
|
|
604
|
+
51. }
|
|
605
|
+
52. }
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
[DecorativeComplex.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeComplex.ets#L16-L68)
|
|
609
|
+
|
|
610
|
+
### @Provider重名时,@Consumer向上查找其最近的@Provider
|
|
611
|
+
|
|
612
|
+
@Provider可以在组件树上重名,@Consumer会向上查找其最近父节点的@Provider的数据。
|
|
613
|
+
|
|
614
|
+
```
|
|
615
|
+
1. @Entry
|
|
616
|
+
2. @ComponentV2
|
|
617
|
+
3. struct Index {
|
|
618
|
+
4. @Provider() val: number = 10;
|
|
619
|
+
|
|
620
|
+
6. build() {
|
|
621
|
+
7. Column() {
|
|
622
|
+
8. Parent()
|
|
623
|
+
9. }
|
|
624
|
+
10. }
|
|
625
|
+
11. }
|
|
626
|
+
|
|
627
|
+
13. @ComponentV2
|
|
628
|
+
14. struct Parent {
|
|
629
|
+
15. @Provider() val: number = 20;
|
|
630
|
+
16. @Consumer('val') val2: number = 0; // 10
|
|
631
|
+
|
|
632
|
+
18. build() {
|
|
633
|
+
19. Column() {
|
|
634
|
+
20. Text(`${this.val2}`)
|
|
635
|
+
21. Child()
|
|
636
|
+
22. }
|
|
637
|
+
23. }
|
|
638
|
+
24. }
|
|
639
|
+
|
|
640
|
+
26. @ComponentV2
|
|
641
|
+
27. struct Child {
|
|
642
|
+
28. @Consumer() val: number = 0; // 20
|
|
643
|
+
|
|
644
|
+
30. build() {
|
|
645
|
+
31. Column() {
|
|
646
|
+
32. Text(`${this.val}`)
|
|
647
|
+
33. }
|
|
648
|
+
34. }
|
|
649
|
+
35. }
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
[ProviderSame.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/ProviderSame.ets#L16-L52)
|
|
653
|
+
|
|
654
|
+
上面的例子中:
|
|
655
|
+
|
|
656
|
+
* Parent中的@Consumer向上查找,查找到Index中定义的@Provider() val: number = 10,初始化为10。
|
|
657
|
+
* Child中的@Consumer向上查找,查找到Parent中定义的@Provider() val: number = 20后停止,初始化为20。
|
|
658
|
+
|
|
659
|
+
### @Provider和@Consumer初始化@Param
|
|
660
|
+
|
|
661
|
+
@Provider和@Consumer装饰的变量可以初始化子组件中@Param装饰的变量。
|
|
662
|
+
|
|
663
|
+
```
|
|
664
|
+
1. @Entry
|
|
665
|
+
2. @ComponentV2
|
|
666
|
+
3. struct Index {
|
|
667
|
+
4. @Provider() val: number = 10;
|
|
668
|
+
|
|
669
|
+
6. build() {
|
|
670
|
+
7. Column() {
|
|
671
|
+
8. Text(`Index @Provider val: ${this.val}`).fontSize(30)
|
|
672
|
+
9. // @Provider装饰的变量val可以初始化@Param装饰的变量val2
|
|
673
|
+
10. Parent({ val2: this.val })
|
|
674
|
+
11. }
|
|
675
|
+
12. }
|
|
676
|
+
13. }
|
|
677
|
+
|
|
678
|
+
15. @ComponentV2
|
|
679
|
+
16. struct Parent {
|
|
680
|
+
17. @Consumer() val: number = 0;
|
|
681
|
+
18. @Require @Param val2: number;
|
|
682
|
+
|
|
683
|
+
20. build() {
|
|
684
|
+
21. Column() {
|
|
685
|
+
22. Text(`Parent @Consumer val: ${this.val}`).fontSize(30)
|
|
686
|
+
23. Button('change val').onClick(() => {
|
|
687
|
+
24. this.val++;
|
|
688
|
+
25. })
|
|
689
|
+
26. Text(`Parent @Param val2: ${this.val2}`).fontSize(30)
|
|
690
|
+
27. // @Consumer装饰的变量val可以初始化@Param装饰的变量val
|
|
691
|
+
28. Child({ val: this.val })
|
|
692
|
+
29. }.border({ width: 2, color: Color.Green })
|
|
693
|
+
30. }
|
|
694
|
+
31. }
|
|
695
|
+
|
|
696
|
+
33. @ComponentV2
|
|
697
|
+
34. struct Child {
|
|
698
|
+
35. @Require @Param val: number;
|
|
699
|
+
|
|
700
|
+
37. build() {
|
|
701
|
+
38. Column() {
|
|
702
|
+
39. Text(`Child @Param val ${this.val}`).fontSize(30)
|
|
703
|
+
40. }.border({ width: 2, color: Color.Pink })
|
|
704
|
+
41. }
|
|
705
|
+
42. }
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
[DecorativeInitialized.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/DecorativeInitialized.ets#L16-L57)
|
|
709
|
+
|
|
710
|
+
上面的例子中:
|
|
711
|
+
|
|
712
|
+
* Index中@Provider装饰的变量val与Parent中@Consumer装饰的变量val建立双向数据绑定。Parent中@Param装饰的变量val2接收Index中数据源val的数据,并同步其变化。Child中@Param装饰的变量val接收Parent中数据源val的数据,并同步其变化。
|
|
713
|
+
* 点击Parent中的按钮,触发@Consumer() val的变化,变化同步给Index中的@Provider() val和Child中的@Param val,对应UI刷新。
|
|
714
|
+
* Index中@Provider() val的变化同步给Parent中的@Param val2,对应UI刷新。
|
|
715
|
+
|
|
716
|
+
### @Consumer在跨BuilderNode场景下和@Provider建立双向同步过程
|
|
717
|
+
|
|
718
|
+
说明
|
|
719
|
+
|
|
720
|
+
从API version 23开始,支持跨BuilderNode配对@Provider和@Consumer。
|
|
721
|
+
|
|
722
|
+
下面给出一个示例,实现如下功能:
|
|
723
|
+
|
|
724
|
+
1. BuilderNode通过[全局自定义构建函数](../../../../学习UI范式基本语法/组件扩展/@Builder装饰器:自定义构建函数/arkts-builder.md#全局自定义构建函数)构建组件树,组件树的根[FrameNode](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/arkui/FrameNode/js-apis-arkui-framenode.md>)节点可通过[getFrameNode](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/arkui/BuilderNode/js-apis-arkui-buildernode.md#getframenode>)获取,该节点可直接由[NodeController](<../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS API/UI界面/arkui/NodeController/js-apis-arkui-nodecontroller.md>)返回并挂载于[NodeContainer](../../../../../../../../harmonyos-references/ArkUI(方舟UI框架)/ArkTS组件/自定义占位组件/NodeContainer/ts-basic-components-nodecontainer.md)节点下。
|
|
725
|
+
2. 挂载到自定义组件节点树时,BuilderNode会通过addBuilderNode方法挂载在自定义组件下,此时BuilderNode节点下的@Consumer会向上查找@Provider,根据key的匹配规则找到最近的@Provider后,会和@Provider建立双向同步关系。如果找不到配对的@Provider,则@Consumer仍使用默认值。
|
|
726
|
+
3. 建立双向同步的关系后,如果@Provider装饰变量的值和@Consumer的默认值不同,则会回调@Consumer的@Monitor方法,以及与@Consumer有同步关系的变量的@Monitor方法,例如:@Consumer通知其子组件中的@Param触发@Monitor方法。
|
|
727
|
+
4. BuilderNode从组件树卸载后,@Consumer会再次试图查找对应的@Provider,如果发现从组件树卸载后无法再找到之前配对的@Provider,则断开和@Provider的双向同步关系,@Consumer装饰的变量恢复成默认值。
|
|
728
|
+
5. @Consumer断开和@Provider的连接,恢复成默认值时,会判断@Consumer装饰变量的值相对于从@Provider变为@Consumer的默认值是否有变化,如果有变化,则会回调@Consumer的@Monitor方法以及与该@Consumer存在同步关系的变量的@Monitor方法。
|
|
729
|
+
|
|
730
|
+
```
|
|
731
|
+
1. import { BuilderNode, FrameNode, NodeController } from '@kit.ArkUI';
|
|
732
|
+
|
|
733
|
+
3. @Builder
|
|
734
|
+
4. function buildText() {
|
|
735
|
+
5. TestRemove()
|
|
736
|
+
6. }
|
|
737
|
+
|
|
738
|
+
8. let globalBuilderNode: BuilderNode<[]> | null = null;
|
|
739
|
+
|
|
740
|
+
10. class TextNodeController extends NodeController {
|
|
741
|
+
11. private rootNode: FrameNode | null = null;
|
|
742
|
+
12. private uiContext: UIContext | null = null;
|
|
743
|
+
|
|
744
|
+
14. constructor() {
|
|
745
|
+
15. super();
|
|
746
|
+
16. }
|
|
747
|
+
|
|
748
|
+
18. makeNode(context: UIContext): FrameNode | null {
|
|
749
|
+
19. this.rootNode = new FrameNode(context);
|
|
750
|
+
20. this.uiContext = context;
|
|
751
|
+
21. return this.rootNode;
|
|
752
|
+
22. }
|
|
753
|
+
|
|
754
|
+
24. addBuilderNode(): void {
|
|
755
|
+
25. if (globalBuilderNode === null && this.uiContext) {
|
|
756
|
+
26. globalBuilderNode = new BuilderNode(this.uiContext);
|
|
757
|
+
27. // 构建BuilderNode,TestRemove作为子组件
|
|
758
|
+
28. globalBuilderNode.build(wrapBuilder<[]>(buildText), undefined, { enableProvideConsumeCrossing: true });
|
|
759
|
+
29. }
|
|
760
|
+
30. if (this.rootNode && globalBuilderNode) {
|
|
761
|
+
31. this.rootNode.appendChild(globalBuilderNode.getFrameNode());
|
|
762
|
+
32. }
|
|
763
|
+
33. }
|
|
764
|
+
|
|
765
|
+
35. removeBuilderNode(): void {
|
|
766
|
+
36. if (this.rootNode && globalBuilderNode) {
|
|
767
|
+
37. this.rootNode.removeChild(globalBuilderNode.getFrameNode());
|
|
768
|
+
38. }
|
|
769
|
+
39. }
|
|
770
|
+
|
|
771
|
+
41. disposeNode(): void {
|
|
772
|
+
42. if (this.rootNode && globalBuilderNode) {
|
|
773
|
+
43. globalBuilderNode.dispose();
|
|
774
|
+
44. }
|
|
775
|
+
45. }
|
|
776
|
+
46. }
|
|
777
|
+
|
|
778
|
+
48. @Entry
|
|
779
|
+
49. @ComponentV2
|
|
780
|
+
50. struct RemoChildDisconnectProvider {
|
|
781
|
+
51. @Provider() content: string = 'Index: hello world';
|
|
782
|
+
52. @Monitor('content')
|
|
783
|
+
53. providerWatch() {
|
|
784
|
+
54. console.info(`Provider change ${this.content}`);
|
|
785
|
+
55. }
|
|
786
|
+
|
|
787
|
+
57. controllerIndex: TextNodeController = new TextNodeController();
|
|
788
|
+
|
|
789
|
+
59. build() {
|
|
790
|
+
60. Column({ space: 8 }) {
|
|
791
|
+
61. Text(`Provider: ${this.content}`)
|
|
792
|
+
|
|
793
|
+
63. // 添加BuilderNode,@Consumer与@Provider建立双向同步
|
|
794
|
+
64. Button('add child')
|
|
795
|
+
65. .onClick(() => {
|
|
796
|
+
66. this.controllerIndex.addBuilderNode();
|
|
797
|
+
67. })
|
|
798
|
+
|
|
799
|
+
69. // 移除BuilderNode,@Consumer与@Provider断开连接,恢复默认值
|
|
800
|
+
70. Button('remove child')
|
|
801
|
+
71. .onClick(() => {
|
|
802
|
+
72. this.controllerIndex.removeBuilderNode();
|
|
803
|
+
73. })
|
|
804
|
+
|
|
805
|
+
75. // 释放BuilderNode的子节点TestRemove,随后该子节点销毁,触发子节点的aboutToDisappear回调
|
|
806
|
+
76. Button('dispose child')
|
|
807
|
+
77. .onClick(() => {
|
|
808
|
+
78. this.controllerIndex.disposeNode();
|
|
809
|
+
79. })
|
|
810
|
+
|
|
811
|
+
81. // @Provider/@Consumer双向同步更新
|
|
812
|
+
82. Button('change Provider')
|
|
813
|
+
83. .onClick(() => {
|
|
814
|
+
84. this.content += 'Pro';
|
|
815
|
+
85. })
|
|
816
|
+
86. NodeContainer(this.controllerIndex)
|
|
817
|
+
87. }
|
|
818
|
+
88. .width('100%')
|
|
819
|
+
89. .height('100%')
|
|
820
|
+
90. }
|
|
821
|
+
91. }
|
|
822
|
+
|
|
823
|
+
93. @ComponentV2
|
|
824
|
+
94. struct TestRemove {
|
|
825
|
+
95. @Consumer() content: string = 'default value';
|
|
826
|
+
96. @Monitor('content')
|
|
827
|
+
97. consumerWatch() {
|
|
828
|
+
98. console.info(`Consumer change ${this.content}`);
|
|
829
|
+
99. }
|
|
830
|
+
|
|
831
|
+
101. aboutToDisappear() {
|
|
832
|
+
102. console.info(`TestRemove aboutToDisappear`);
|
|
833
|
+
103. }
|
|
834
|
+
|
|
835
|
+
105. build() {
|
|
836
|
+
106. Column() {
|
|
837
|
+
107. Text('Consumer ' + this.content)
|
|
838
|
+
|
|
839
|
+
109. // @Provider和@Consumer绑定的Text组件刷新,并回调@Provider和@Consumer的@Monitor方法
|
|
840
|
+
110. Button('change cc')
|
|
841
|
+
111. .onClick(() => {
|
|
842
|
+
112. this.content += 'cc';
|
|
843
|
+
113. })
|
|
844
|
+
114. }
|
|
845
|
+
115. }
|
|
846
|
+
116. }
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
[BuilderNode.ets](https://gitcode.com/HarmonyOS_Samples/guide-snippets/blob/HarmonyOS-feature-20260402/ArkUISample/ProviderConsumer/entry/src/main/ets/homePage/BuilderNode.ets#L15-L132)
|
|
850
|
+
|
|
851
|
+
上面的例子中:
|
|
852
|
+
|
|
853
|
+
* 点击add Child,TestRemove中@Consumer向上找到最近的RemoChildDisconnectProvider中的@Provider,将@Consumer从默认值更新为@Provider的值,并回调@Consumer的@Monitor方法。
|
|
854
|
+
* @Provider和@Consumer配对后,建立双向同步关系。点击change Provider和Text(change cc),@Provider和@Consumer绑定的Text组件刷新,并回调@Provider和@Consumer的@Monitor方法。
|
|
855
|
+
* 点击remove Child,BuilderNode子节点从组件树卸载,TestRemove中的@Consumer和RemoChildDisconnectProvider中的@Provider断开连接,TestRemove中的@Consumer恢复成默认值,并回调@Consumer的@Monitor方法。
|
|
856
|
+
* 点击dispose Child,释放BuilderNode下的子节点TestRemove,随后该子节点销毁,执行aboutToDisappear回调。
|