@buaa_smat/hometrans 0.1.0 → 0.1.2

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.
Files changed (136) hide show
  1. package/README.md +141 -124
  2. package/agents/build-fixer.md +1 -0
  3. package/agents/code-review-fix.md +1 -0
  4. package/agents/code-reviewer.md +1 -0
  5. package/agents/logic-coding.md +1 -0
  6. package/agents/logic-context-builder.md +1 -0
  7. package/agents/review-fixer.md +1 -0
  8. package/agents/self-test-fixer.md +1 -0
  9. package/agents/self-tester.md +260 -233
  10. package/agents/spec-generator.md +1 -0
  11. package/agents/test-tools/autotest/README.md +223 -0
  12. package/agents/test-tools/autotest/config.yaml.example +58 -0
  13. package/agents/test-tools/autotest/pyproject.toml +16 -0
  14. package/agents/test-tools/autotest/report_tool.py +759 -0
  15. package/agents/test-tools/autotest/self_test_runner.py +773 -0
  16. package/agents/test-tools/autotest/testcases_schema.md +143 -0
  17. package/agents/test-tools/autotest/testcases_tool.py +215 -0
  18. package/agents/test-tools/autotest/uv.lock +3156 -0
  19. package/agents/test-tools/harmony_autotest-0.1.0-py3-none-any.whl +0 -0
  20. package/agents/test-tools/hypium-6.1.0.210-py3-none-any.whl +0 -0
  21. package/agents/test-tools/hypium_mcp-0.6.5-py3-none-any.whl +0 -0
  22. package/agents/test-tools/xdevice-6.1.0.210-py3-none-any.whl +0 -0
  23. package/agents/test-tools/xdevice_devicetest-6.1.0.210-py3-none-any.whl +0 -0
  24. package/agents/test-tools/xdevice_ohos-6.1.0.210-py3-none-any.whl +0 -0
  25. package/dist/cli/config-store.js +27 -2
  26. package/dist/cli/config.js +17 -6
  27. package/dist/cli/index.js +3 -2
  28. package/dist/cli/init.js +135 -22
  29. package/dist/cli/mcp.js +2 -2
  30. package/dist/context/index.js +165 -69
  31. package/package.json +59 -60
  32. package/skills/code-dev-review-fix/SKILL.md +279 -0
  33. package/skills/code-dev-review-fix-workspace/evals/evals.json +56 -0
  34. package/skills/code-dev-review-fix-workspace/iteration-1/routing-results.md +23 -0
  35. package/skills/convert_pipeline/SKILL.md +423 -439
  36. package/skills/hmos-resources-convert/SKILL.md +623 -0
  37. package/skills/hmos-resources-convert/evals/evals.json +171 -0
  38. package/skills/hmos-resources-convert/references/conversion-rules.md +663 -0
  39. package/skills/hmos-resources-convert/references/dependency-analysis-rules.md +388 -0
  40. package/skills/hmos-resources-convert/references/resource-mapping-rules.md +457 -0
  41. package/skills/hmos-resources-convert/references/xml-drawable-to-svg-rules.md +513 -0
  42. package/skills/hmos-resources-convert/template/AppScope/app.json5 +10 -0
  43. package/skills/hmos-resources-convert/template/AppScope/resources/base/element/string.json +8 -0
  44. package/skills/hmos-resources-convert/template/AppScope/resources/base/media/background.png +0 -0
  45. package/skills/hmos-resources-convert/template/AppScope/resources/base/media/foreground.png +0 -0
  46. package/skills/hmos-resources-convert/template/AppScope/resources/base/media/layered_image.json +7 -0
  47. package/skills/hmos-resources-convert/template/build-profile.json5 +42 -0
  48. package/skills/hmos-resources-convert/template/code-linter.json5 +32 -0
  49. package/skills/hmos-resources-convert/template/entry/build-profile.json5 +33 -0
  50. package/skills/hmos-resources-convert/template/entry/hvigorfile.ts +6 -0
  51. package/skills/hmos-resources-convert/template/entry/obfuscation-rules.txt +23 -0
  52. package/skills/hmos-resources-convert/template/entry/oh-package.json5 +10 -0
  53. package/skills/hmos-resources-convert/template/entry/src/main/ets/entryability/EntryAbility.ets +48 -0
  54. package/skills/hmos-resources-convert/template/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets +16 -0
  55. package/skills/hmos-resources-convert/template/entry/src/main/ets/pages/Index.ets +23 -0
  56. package/skills/hmos-resources-convert/template/entry/src/main/module.json5 +55 -0
  57. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/element/color.json +8 -0
  58. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/element/float.json +8 -0
  59. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/element/string.json +16 -0
  60. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/background.png +0 -0
  61. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/foreground.png +0 -0
  62. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/layered_image.json +7 -0
  63. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/startIcon.png +0 -0
  64. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/profile/backup_config.json +3 -0
  65. package/skills/hmos-resources-convert/template/entry/src/main/resources/base/profile/main_pages.json +5 -0
  66. package/skills/hmos-resources-convert/template/entry/src/main/resources/dark/element/color.json +8 -0
  67. package/skills/hmos-resources-convert/template/entry/src/mock/mock-config.json5 +2 -0
  68. package/skills/hmos-resources-convert/template/entry/src/ohosTest/ets/test/Ability.test.ets +35 -0
  69. package/skills/hmos-resources-convert/template/entry/src/ohosTest/ets/test/List.test.ets +5 -0
  70. package/skills/hmos-resources-convert/template/entry/src/ohosTest/module.json5 +16 -0
  71. package/skills/hmos-resources-convert/template/entry/src/test/List.test.ets +5 -0
  72. package/skills/hmos-resources-convert/template/entry/src/test/LocalUnit.test.ets +33 -0
  73. package/skills/hmos-resources-convert/template/hvigor/hvigor-config.json5 +23 -0
  74. package/skills/hmos-resources-convert/template/hvigorfile.ts +6 -0
  75. package/skills/hmos-resources-convert/template/oh-package-lock.json5 +28 -0
  76. package/skills/hmos-resources-convert/template/oh-package.json5 +10 -0
  77. package/skills/hmos-resources-convert/tools/apktool.bat +85 -0
  78. package/skills/hmos-resources-convert/tools/apktool_3.0.1.jar +0 -0
  79. package/skills/hmos-ui-align/SKILL.md +182 -0
  80. package/skills/hmos-ui-align/config-example.json +11 -0
  81. package/skills/hmos-ui-align/config.json +11 -0
  82. package/skills/hmos-ui-align/diff_analysis.md +53 -0
  83. package/skills/hmos-ui-align/page_align.md +62 -0
  84. package/skills/hmos-ui-align/readme.md +231 -0
  85. package/skills/hmos-ui-align/references/Comparison_Template.md +2 -0
  86. package/skills/hmos-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
  87. package/skills/hmos-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
  88. package/skills/hmos-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
  89. package/skills/hmos-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
  90. package/skills/hmos-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
  91. package/skills/hmos-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
  92. package/skills/hmos-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
  93. package/skills/hmos-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
  94. package/skills/hmos-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
  95. package/skills/hmos-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
  96. package/skills/hmos-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
  97. package/skills/hmos-ui-align/references/MVVM/345/274/200/345/217/221/346/226/207/346/241/243/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md +911 -0
  98. package/skills/hmos-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
  99. package/skills/hmos-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
  100. package/skills/hmos-ui-align/references/UI_Analysis_Template.md +4 -0
  101. package/skills/hmos-ui-align/references/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +2535 -0
  102. package/skills/hmos-ui-align/references/android-to-harmonyOS-ui-interaction-mapping-reference.md +555 -0
  103. package/skills/hmos-ui-align/references/android-to-harmonyOS-ui-layout-mapping-reference.md +117 -0
  104. package/skills/hmos-ui-align/scripts/app_feature_verify.py +443 -0
  105. package/skills/hmos-ui-align/scripts/navigation-capure.md +37 -0
  106. package/skills/hmos-ui-align/scripts/page_capture.py +592 -0
  107. package/skills/hmos-ui-align-batch/SKILL.md +99 -0
  108. package/skills/hmos-ui-align-batch/references/conversion-procedure.md +180 -0
  109. package/skills/hmos-ui-align-batch/references/mappings/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +2535 -0
  110. package/skills/hmos-ui-align-batch/references/mappings/android-to-harmonyOS-ui-interaction-mapping-reference.md +555 -0
  111. package/skills/hmos-ui-align-batch/references/mappings/android-to-harmonyOS-ui-layout-mapping-reference.md +117 -0
  112. package/skills/hmos-ui-align-batch/references/mvvm/@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
  113. package/skills/hmos-ui-align-batch/references/mvvm/@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
  114. package/skills/hmos-ui-align-batch/references/mvvm/@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
  115. package/skills/hmos-ui-align-batch/references/mvvm/@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
  116. package/skills/hmos-ui-align-batch/references/mvvm/@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
  117. package/skills/hmos-ui-align-batch/references/mvvm/@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
  118. package/skills/hmos-ui-align-batch/references/mvvm/@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
  119. package/skills/hmos-ui-align-batch/references/mvvm/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
  120. package/skills/hmos-ui-align-batch/references/mvvm/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
  121. package/skills/hmos-ui-align-batch/references/mvvm/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
  122. package/skills/hmos-ui-align-batch/references/mvvm/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md +911 -0
  123. package/skills/hmos-ui-align-batch/references/mvvm/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
  124. package/skills/hmos-ui-align-batch/references/mvvm//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
  125. package/skills/hmos-ui-align-batch/scripts/android_parse_fast.py +1606 -0
  126. package/skills/self-test/SKILL.md +369 -0
  127. package/skills/self-test/readme.md +309 -0
  128. package/skills/spec-generator-skill/SKILL.md +332 -0
  129. package/skills/spec-generator-skill/references/android-platform-tokens.md +105 -0
  130. package/skills/spec-generator-skill/references/spec-sample-1.md +78 -0
  131. package/skills/spec-generator-skill/references/spec-sample-2.md +58 -0
  132. package/skills/spec-generator-skill/references/spec-sample-3.md +116 -0
  133. package/skills/spec-generator-skill/references/step4-report-template.md +33 -0
  134. package/agents/self-test-setup.md +0 -165
  135. package/dist/context/resources/sdkConfig.json +0 -24
  136. package/src/context/resources/sdkConfig.json +0 -24
@@ -0,0 +1,1033 @@
1
+ # @Prop装饰器:父子单向同步
2
+
3
+ @Prop装饰的变量可以和父组件建立单向同步关系。
4
+
5
+ 在阅读@Prop文档前,建议开发者首先了解[@State](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state)的基本用法。最佳实践请参考[状态管理最佳实践](https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-status-management)。常见问题请参考[状态管理常见问题](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state-management-faq)。
6
+
7
+ > **说明:**
8
+ >
9
+ > 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
10
+ >
11
+ > 从API version 11开始,该装饰器支持在元服务中使用。
12
+
13
+ ## 概述
14
+
15
+ @Prop装饰的变量具有以下特性:
16
+
17
+ - @Prop装饰的变量允许本地修改,但修改不会同步回父组件。
18
+
19
+ - 当数据源更改时,@Prop装饰的变量都会更新,并且会覆盖本地所有更改。
20
+
21
+ ## 装饰器使用规则说明
22
+
23
+ | @Prop变量装饰器 | 说明 |
24
+ | --- | --- |
25
+ | 装饰器参数 | 无。 |
26
+ | 同步类型 | 单向同步。对父组件状态变量值的修改,将同步给子组件@Prop装饰的变量,子组件@Prop装饰的变量的修改不会同步到父组件的状态变量上。嵌套类型的场景请参考[观察变化](#观察变化)。 |
27
+ | 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。API version 10开始支持[Date类型](#装饰date类型变量)。API version 11及以上支持[Map](#装饰map类型变量)、[Set](#装饰set类型变量)类型、undefined和null类型、ArkUI框架定义的联合类型[Length](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-types#length)、[ResourceStr](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-types#resourcestr)、[ResourceColor](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-types#resourcecolor)类型以及这些类型的联合类型,示例见[Prop支持联合类型实例](#prop支持联合类型实例)。支持类型的场景请参考[观察变化](#观察变化)。 |
28
+ | 不允许装饰的变量类型 | 不支持装饰Function类型。 |
29
+ | 嵌套传递层数 | 在组件复用场景,建议@Prop深度嵌套数据不要超过5层,嵌套太多会导致深拷贝占用的空间过大以及GarbageCollection(垃圾回收),引起性能问题,此时更建议使用[@ObjectLink](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-observed-and-objectlink)。 |
30
+ | 被装饰变量的初始值 | 允许本地初始化。API version 11及以上,如果和[@Require](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-require)结合使用,则必须父组件构造传参。 |
31
+
32
+ ## 变量的传递/访问规则说明
33
+
34
+ | 装饰器使用规则 | 说明 |
35
+ | --- | --- |
36
+ | 从父组件初始化 | 如果本地有初始化,则是可选的,初始化行为和[@State](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state#变量的传递访问规则说明)保持一致。没有的话,则必选,支持父组件中的常规变量(常规变量对@Prop赋值,只是数值的初始化,常规变量的变化不会触发UI刷新。只有状态变量才能触发UI刷新)、[@State](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state)、[@Link](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-link)、@Prop、[@Provide](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-provide-and-consume)、[@Consume](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-provide-and-consume)、[@ObjectLink](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-observed-and-objectlink)、[@StorageLink](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-appstorage#storagelink)、[@StorageProp](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-appstorage#storageprop)、[@LocalStorageLink](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-localstorage#localstoragelink)和[@LocalStorageProp](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-localstorage#localstorageprop)去初始化子组件中的@Prop变量。 |
37
+ | 用于初始化子组件 | @Prop支持初始化子组件中的常规变量、@State、@Link、@Prop、@Provide。 |
38
+ | 是否支持组件外访问 | @Prop装饰的变量是私有的,只能在组件内访问。 |
39
+
40
+ 初始化规则图示:
41
+
42
+ ![初始化规则图示](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/3a/v3/5yKoRDb4QpO1uc6W-Ss7mA/zh-cn_image_0000002535948084.png)
43
+
44
+ ## 观察变化和行为表现
45
+
46
+ ### 观察变化
47
+
48
+ @Prop装饰的数据可以观察到以下变化。
49
+
50
+ - 当装饰支持类型,可以观察到赋值的变化。简单类型完整示例请参考[父组件@State到子组件@Prop简单数据类型同步](#父组件state到子组件prop简单数据类型同步)。
51
+
52
+ ```ts
53
+ // 简单类型
54
+ @Prop count: number;
55
+ // 赋值的变化可以被观察到
56
+ this.count = 1;
57
+ // 复杂类型
58
+ @Prop title: Model;
59
+ // 可以观察到赋值的变化
60
+ this.title = new Model('Hi');
61
+ ```
62
+
63
+ - 当装饰的类型是Object或者class复杂类型时,可以观察到自身的赋值和第一层的属性的变化,属性即object.keys(observedObject)返回的所有属性。复杂类型完整示例请参考[从父组件中的@State类对象属性到@Prop简单类型的同步](#从父组件中的state类对象属性到prop简单类型的同步)。
64
+
65
+ ```TypeScript
66
+ // 定义嵌套类
67
+ class Info {
68
+ public value: string;
69
+
70
+ constructor(value: string) {
71
+ this.value = value;
72
+ }
73
+ }
74
+
75
+ class Model {
76
+ public value: string;
77
+ public info: Info;
78
+
79
+ constructor(value: string, info: Info) {
80
+ this.value = value;
81
+ this.info = info;
82
+ }
83
+ }
84
+ ```
85
+
86
+ ```TypeScript
87
+ @Prop title: Model;
88
+ ```
89
+
90
+ ```TypeScript
91
+ // 可以观察到第一层的变化
92
+ this.title.value = 'Hi';
93
+ ```
94
+
95
+ ```TypeScript
96
+ // 观察不到第二层的变化
97
+ this.title.info.value = 'ArkUI';
98
+ ```
99
+
100
+ 对于嵌套场景,如果class是被@Observed装饰的,可以观察到class属性的变化,示例请参考[@Prop嵌套场景](#prop嵌套场景)。
101
+
102
+ - 当装饰的类型是数组的时候,可以观察到数组本身的赋值和数组项的添加、删除和更新。数组类型完整示例请参考[父组件@State数组项到子组件@Prop简单数据类型同步](#父组件state数组项到子组件prop简单数据类型同步)。
103
+
104
+ ```ts
105
+ // @Prop装饰的对象为数组时
106
+ @Prop title: string[];
107
+ // 数组自身的赋值可以观察到
108
+ this.title = ['1'];
109
+ // 数组项的赋值可以观察到
110
+ this.title[0] = '2';
111
+ // 删除数组项可以观察到
112
+ this.title.pop();
113
+ // 新增数组项可以观察到
114
+ this.title.push('3');
115
+ ```
116
+
117
+ 对于@State和@Prop的同步场景:
118
+
119
+ - 使用父组件中@State变量的值初始化子组件中的@Prop变量。当@State变量变化时,该变量值也会同步更新至@Prop变量。
120
+
121
+ - @Prop装饰的变量的修改不会影响其数据源@State装饰变量的值。
122
+
123
+ - 除了@State,数据源也可以用@Link或@Prop装饰,对@Prop的同步机制是相同的。
124
+
125
+ - 数据源和@Prop变量的类型需要相同。
126
+
127
+ - 当装饰的对象是Date时,可以观察到Date整体的赋值,同时可通过调用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的属性,详见[装饰Date类型变量](#装饰date类型变量)。
128
+
129
+ - 当装饰的变量是Map时,可以观察到Map整体的赋值,同时可通过调用Map的接口set, clear, delete 更新Map的值。详见[装饰Map类型变量](#装饰map类型变量)。
130
+
131
+ - 当装饰的变量是Set时,可以观察到Set整体的赋值,同时可通过调用Set的接口add, clear, delete 更新Set的值。详见[装饰Set类型变量](#装饰set类型变量)。
132
+
133
+ ### 框架行为
134
+
135
+ 理解@Prop变量值初始化和更新机制,需要了解父组件和子组件的渲染和更新流程。
136
+
137
+ 1. 初始渲染:
138
+ 1. 执行父组件的build()函数,创建子组件的新实例并传递数据源。
139
+ 2. 初始化子组件@Prop装饰的变量。
140
+
141
+ 2. 更新:
142
+ 1. 子组件@Prop更新时,更新仅停留在当前子组件,不会同步回父组件。
143
+ 2. 当父组件的数据源更新时,子组件的@Prop装饰的变量将被来自父组件的数据源重置,所有@Prop装饰变量的本地修改将被父组件的更新覆盖。
144
+
145
+ > **说明:**
146
+ >
147
+ > @Prop同步数据源依赖于数据源所在组件的刷新,而应用进入后台后无法触发刷新,因此应用进入后台后,@Prop无法从数据源更新。在此场景下,若需即时数据同步,推荐使用@Link代替。
148
+
149
+ 以下示例中,当@State装饰的变量message改变时,Father组件会刷新。由于Son组件使用@Prop接收了该变量,因此Father组件刷新的过程中会使用message的最新值去更新@Prop的值。@Prop更新后,会触发Son组件的刷新。
150
+
151
+ ```TypeScript
152
+ @Component
153
+ struct Son {
154
+ @Prop message: string = 'Hi';
155
+
156
+ build() {
157
+ Column() {
158
+ Text(this.message)
159
+ }
160
+ }
161
+ }
162
+
163
+ @Entry
164
+ @Component
165
+ struct Father {
166
+ @State message: string = 'Hello';
167
+
168
+ build() {
169
+ Column() {
170
+ Text(this.message)
171
+ Button(`father click`).onClick(() => {
172
+ this.message += '*';
173
+ })
174
+ Son({ message: this.message })
175
+ }
176
+ }
177
+ }
178
+ ```
179
+
180
+ ## 限制条件
181
+
182
+ - @Prop装饰变量时会进行深拷贝,在拷贝的过程中除了基本类型、Map、Set、Date、Array外,都会丢失类型。例如,对于通过NAPI提供的复杂类型(如[PixelMap](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-image-pixelmap)),由于其部分实现在Native侧,因此无法在ArkTS侧通过深拷贝获得完整的数据;同样,RegExp类型在拷贝过程中会丢失原类型,导致被@Prop装饰后无法调用正则相关函数。
183
+
184
+ - 父组件传入undefined时,@Prop装饰的变量仍使用本地默认值进行初始化。
185
+
186
+ ```TypeScript
187
+ @Entry
188
+ @Component
189
+ struct Parent {
190
+ @State count: number | undefined = undefined;
191
+
192
+ build() {
193
+ Column() {
194
+ Text(`Parent count value: ${this.count}`)
195
+ .fontSize(20)
196
+ .margin(10)
197
+ Child({ count: this.count })
198
+ }
199
+ }
200
+ }
201
+
202
+ @Component
203
+ struct Child {
204
+ @Prop count: number | undefined = 0;
205
+
206
+ build() {
207
+ Column() {
208
+ Text(`Child count value: ${this.count}`)
209
+ .fontSize(20)
210
+ .margin(10)
211
+ }
212
+ }
213
+ }
214
+ ```
215
+
216
+ ## 使用场景
217
+
218
+ ### 父组件@State到子组件@Prop简单数据类型同步
219
+
220
+ 以下示例是@State到子组件@Prop简单数据同步,父组件ParentComponent的状态变量countDownStartValue初始化子组件CountDownComponent中@Prop装饰的count,点击"Try again",count的修改仅保留在CountDownComponent,不会同步给父组件ParentComponent。
221
+
222
+ ParentComponent的状态变量countDownStartValue的变化将重置CountDownComponent的count。
223
+
224
+ ```TypeScript
225
+ @Component
226
+ struct CountDownComponent {
227
+ @Prop count: number = 0;
228
+ costOfOneAttempt: number = 1;
229
+
230
+ build() {
231
+ Column() {
232
+ if (this.count > 0) {
233
+ Text(`You have ${this.count} Nuggets left`)
234
+ } else {
235
+ Text('Game over!')
236
+ }
237
+ // @Prop装饰的变量不会同步给父组件
238
+ Button(`Try again`).onClick(() => {
239
+ this.count -= this.costOfOneAttempt;
240
+ })
241
+ }
242
+ }
243
+ }
244
+
245
+ @Entry
246
+ @Component
247
+ struct ParentComponent {
248
+ @State countDownStartValue: number = 10;
249
+
250
+ build() {
251
+ Column() {
252
+ Text(`Grant ${this.countDownStartValue} nuggets to play.`)
253
+ // 父组件的数据源的修改会同步给子组件
254
+ Button(`+1 - Nuggets in New Game`).onClick(() => {
255
+ this.countDownStartValue += 1;
256
+ })
257
+ // 父组件的修改会同步给子组件
258
+ Button(`-1 - Nuggets in New Game`).onClick(() => {
259
+ this.countDownStartValue -= 1;
260
+ })
261
+ CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
262
+ }
263
+ }
264
+ }
265
+ ```
266
+
267
+ 在上面的示例中:
268
+
269
+ 1. CountDownComponent子组件首次创建时其@Prop装饰的count变量将从父组件@State装饰的countDownStartValue变量初始化。
270
+
271
+ 2. 按"+1"或"-1"按钮时,父组件的@State装饰的countDownStartValue值会变化,这将触发父组件重新渲染,在父组件重新渲染过程中会刷新使用countDownStartValue状态变量的UI组件,并单向同步更新CountDownComponent子组件中的count值。
272
+
273
+ 3. 更新count状态变量值也会触发CountDownComponent的重新渲染,在重新渲染过程中,评估使用count状态变量的if语句条件(this.count > 0),并执行true分支中的使用count状态变量的UI组件相关描述来更新Text组件的UI显示。
274
+
275
+ 4. 当按下子组件CountDownComponent的"Try again"按钮时,其@Prop变量count将被更改,但是count值的更改不会影响父组件的countDownStartValue值。
276
+
277
+ 5. 父组件的countDownStartValue值变化时,父组件的修改将覆盖掉子组件CountDownComponent中count本地的修改。
278
+
279
+ ### 父组件@State数组项到子组件@Prop简单数据类型同步
280
+
281
+ 父组件中@State如果装饰数组类型的变量,其数组项也可以初始化@Prop。以下示例中,父组件Index中@State装饰数组arr,将其数组项初始化子组件Child中@Prop装饰的value。
282
+
283
+ ```TypeScript
284
+ @Component
285
+ struct Child {
286
+ @Prop value: number = 0;
287
+
288
+ build() {
289
+ Text(`${this.value}`)
290
+ .fontSize(50)
291
+ .onClick(() => {
292
+ this.value++;
293
+ })
294
+ }
295
+ }
296
+
297
+ @Entry
298
+ @Component
299
+ struct Index {
300
+ @State arr: number[] = [1, 2, 3];
301
+
302
+ build() {
303
+ Row() {
304
+ Column() {
305
+ Child({ value: this.arr[0] })
306
+ Child({ value: this.arr[1] })
307
+ Child({ value: this.arr[2] })
308
+
309
+ Divider().height(5)
310
+
311
+ ForEach(this.arr,
312
+ (item: number) => {
313
+ Child({ value: item })
314
+ },
315
+ (item: number) => item.toString()
316
+ )
317
+ Text('replace entire arr')
318
+ .fontSize(50)
319
+ .onClick(() => {
320
+ // 两个数组都包含项"3"。
321
+ this.arr = this.arr[0] == 1 ? [3, 4, 5] : [1, 2, 3];
322
+ })
323
+ }
324
+ }
325
+ }
326
+ }
327
+ ```
328
+
329
+ 初始渲染创建6个子组件实例,每个@Prop装饰的变量初始化都在本地拷贝了一份数组项。子组件onClick事件处理程序会更改局部变量值。
330
+
331
+ 如果点击界面上的"1"六次,"2"五次、"3"四次,将所有变量的本地取值都变为"7"。
332
+
333
+ ```
334
+ 7
335
+ 7
336
+ 7
337
+ ——————
338
+ 7
339
+ 7
340
+ 7
341
+ ```
342
+
343
+ 点击replace entire arr后,屏幕将显示以下信息。
344
+
345
+ ```
346
+ 3
347
+ 4
348
+ 5
349
+ ——————
350
+ 7
351
+ 4
352
+ 5
353
+ ```
354
+
355
+ - 在子组件Child中做的所有的修改都不会同步回父组件Index组件,所以即使6个组件显示都为7,但在父组件Index中,this.arr保存的值依旧是[1,2,3]。
356
+
357
+ - 点击replace entire arr,this.arr[0] == 1成立,将this.arr赋值为[3, 4, 5]。
358
+
359
+ - 因为this.arr[0]已更改,Child({value: this.arr[0]})组件将this.arr[0]更新同步到实例@Prop装饰的变量。Child({value: this.arr[1]})和Child({value: this.arr[2]})的情况也类似。
360
+
361
+ - this.arr的更改触发ForEach更新,this.arr更新的前后都有数值为3的数组项:[3, 4, 5] 和[1, 2, 3]。根据diff算法,数组项"3"将被保留,删除"1"和"2"的数组项,添加为"4"和"5"的数组项。这就意味着,数组项"3"的组件不会重新生成,而是将其移动到第一位。所以"3"对应的组件不会更新,此时"3"对应的组件数值为"7",ForEach最终的渲染结果是"7","4","5"。
362
+
363
+ ### 从父组件中的@State类对象属性到@Prop简单类型的同步
364
+
365
+ 如果图书馆有一本图书和两位用户,每位用户都可以将图书标记为已读,此标记行为不会影响其他用户。从代码角度讲,对@Prop图书对象的本地更改不会同步给图书馆组件中的@State图书对象。
366
+
367
+ 在此示例中,图书类可以使用@Observed装饰器,但不是必须的,只有在嵌套结构时需要此装饰器。这一点会在[从父组件中的@State数组项到@Prop class类型的同步](#从父组件中的state数组项到prop-class类型的同步)说明。
368
+
369
+ ```TypeScript
370
+ class Book {
371
+ public title: string;
372
+ public pages: number;
373
+ public readIt: boolean = false;
374
+
375
+ constructor(title: string, pages: number) {
376
+ this.title = title;
377
+ this.pages = pages;
378
+ }
379
+ }
380
+
381
+ @Component
382
+ struct ReaderComp {
383
+ @Prop book: Book = new Book('', 0);
384
+
385
+ build() {
386
+ Row() {
387
+ Text(this.book.title)
388
+ Text(`...has${this.book.pages} pages!`)
389
+ Text(`...${this.book.readIt ? 'I have read' : 'I have not read it'}`)
390
+ .onClick(() => this.book.readIt = true)
391
+ }
392
+ }
393
+ }
394
+
395
+ @Entry
396
+ @Component
397
+ struct Library {
398
+ @State book: Book = new Book('100 secrets of C++', 765);
399
+
400
+ build() {
401
+ Column() {
402
+ ReaderComp({ book: this.book })
403
+ ReaderComp({ book: this.book })
404
+ }
405
+ }
406
+ }
407
+ ```
408
+
409
+ ### 从父组件中的@State数组项到@Prop class类型的同步
410
+
411
+ 以下示例中,更改了@State装饰的allBooks数组中Book对象的属性,但点击"Mark read for everyone"时,没有触发UI更新。这是因为该属性是第二层的嵌套属性,@State装饰器只能观察到第一层属性,不会观察到此属性更改,所以框架不会更新ReaderComp。
412
+
413
+ ```TypeScript
414
+ import { hilog } from '@kit.PerformanceAnalysisKit';
415
+
416
+ const DOMAIN = 0x0001;
417
+ const TAG: string = '[SampleProp]';
418
+ let nextId: number = 1;
419
+
420
+ // @Observed
421
+ class Book {
422
+ public id: number;
423
+ public title: string;
424
+ public pages: number;
425
+ public readIt: boolean = false;
426
+
427
+ constructor(title: string, pages: number) {
428
+ this.id = nextId++;
429
+ this.title = title;
430
+ this.pages = pages;
431
+ }
432
+ }
433
+
434
+ @Component
435
+ struct ReaderComp {
436
+ @Prop book: Book = new Book('', 1);
437
+
438
+ build() {
439
+ Row() {
440
+ Text(` ${this.book ? this.book.title : 'Book is undefined'}`).fontColor('#e6000000')
441
+ Text(` has ${this.book ? this.book.pages : 'Book is undefined'} pages!`).fontColor('#e6000000')
442
+ Text(` ${this.book ? this.book.readIt ? 'I have read' : 'I have not read it' : 'Book is undefined'}`)
443
+ .fontColor('#e6000000')
444
+ .onClick(() => this.book.readIt = true)
445
+ }
446
+ }
447
+ }
448
+
449
+ @Entry
450
+ @Component
451
+ struct Library {
452
+ @State allBooks: Book[] = [new Book('C#', 765), new Book('JS', 652), new Book('TS', 765)];
453
+
454
+ build() {
455
+ Column() {
456
+ Text('library`s all time favorite')
457
+ .width(312)
458
+ .height(40)
459
+ .backgroundColor('#0d000000')
460
+ .borderRadius(20)
461
+ .margin(12)
462
+ .padding({ left: 20 })
463
+ .fontColor('#e6000000')
464
+ ReaderComp({ book: this.allBooks[2] })
465
+ .backgroundColor('#0d000000')
466
+ .width(312)
467
+ .height(40)
468
+ .padding({ left: 20, top: 10 })
469
+ .borderRadius(20)
470
+ .colorBlend('#e6000000')
471
+ Text('Books on loan to a reader')
472
+ .width(312)
473
+ .height(40)
474
+ .backgroundColor('#0d000000')
475
+ .borderRadius(20)
476
+ .margin(12)
477
+ .padding({ left: 20 })
478
+ .fontColor('#e6000000')
479
+ ForEach(this.allBooks, (book: Book) => {
480
+ ReaderComp({ book: book })
481
+ .margin(12)
482
+ .width(312)
483
+ .height(40)
484
+ .padding({ left: 20, top: 10 })
485
+ .backgroundColor('#0d000000')
486
+ .borderRadius(20)
487
+ },
488
+ (book: Book) => book.id.toString())
489
+ Button('Add new')
490
+ .width(312)
491
+ .height(40)
492
+ .margin(12)
493
+ .fontColor('#FFFFFF')
494
+ .onClick(() => {
495
+ this.allBooks.push(new Book('JA', 512));
496
+ })
497
+ Button('Remove first book')
498
+ .width(312)
499
+ .height(40)
500
+ .margin(12)
501
+ .fontColor('#FFFFFF')
502
+ .onClick(() => {
503
+ if (this.allBooks.length > 0) {
504
+ this.allBooks.shift();
505
+ } else {
506
+ hilog.info(DOMAIN, TAG, 'length <= 0');
507
+ }
508
+ })
509
+ Button('Mark read for everyone')
510
+ .width(312)
511
+ .height(40)
512
+ .margin(12)
513
+ .fontColor('#FFFFFF')
514
+ .onClick(() => {
515
+ this.allBooks.forEach((book) => book.readIt = true)
516
+ })
517
+ }
518
+ }
519
+ }
520
+ ```
521
+
522
+ 使用@Observed装饰class Book,Book的属性变化将被观察。需要注意的是,@Prop在子组件装饰的状态变量和父组件的数据源是单向同步关系,即ReaderComp中的@Prop book的修改不会同步给父组件Library。而父组件只会在状态变量发生变化的时候,才会触发UI的重新渲染。
523
+
524
+ ```ts
525
+ @Observed
526
+ class Book {
527
+ public id: number;
528
+ public title: string;
529
+ public pages: number;
530
+ public readIt: boolean = false;
531
+
532
+ constructor(title: string, pages: number) {
533
+ this.id = nextId++;
534
+ this.title = title;
535
+ this.pages = pages;
536
+ }
537
+ }
538
+ ```
539
+
540
+ @Observed装饰的类的实例会被不透明的代理对象包装,此代理可以检测到包装对象内的所有属性更改。如果发生这种情况,此时,代理通知@Prop,@Prop对象值被更新。
541
+
542
+ ![从父组件中的@State数组项到@Prop class类型的同步效果图](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/b2/v3/1KfpfWkBTXu8dzHwGvxJHA/zh-cn_image_0000002566867917.gif)
543
+
544
+ ### @Prop本地初始化不和父组件同步
545
+
546
+ 为了支持@Component装饰的组件复用场景,@Prop支持本地初始化,这样可以让@Prop是否与父组件建立同步关系变得可选。当且仅当@Prop有本地初始化时,从父组件向子组件传递@Prop的数据源才是可选的。
547
+
548
+ 下面的示例中,子组件包含两个@Prop变量:
549
+
550
+ - @Prop customCounter没有本地初始化,所以需要父组件提供数据源去初始化@Prop,并当父组件的数据源变化时,@Prop也将被更新。
551
+
552
+ - @Prop customCounter2有本地初始化,在这种情况下,@Prop依旧允许但非强制父组件同步数据源给@Prop。
553
+
554
+ ```TypeScript
555
+ @Component
556
+ struct MyComponent {
557
+ @Prop customCounter: number;
558
+ @Prop customCounter2: number = 5;
559
+
560
+ build() {
561
+ Column() {
562
+ Row() {
563
+ Text(`From Main: ${this.customCounter}`).fontColor('#ff6b6565').margin({ left: -110, top: 12 })
564
+ }
565
+
566
+ Row() {
567
+ Button('Click to change locally!')
568
+ .width(288)
569
+ .height(40)
570
+ .margin({ left: 30, top: 12 })
571
+ .fontColor('#FFFFFF')
572
+ .onClick(() => {
573
+ this.customCounter2++;
574
+ })
575
+ }
576
+
577
+ Row() {
578
+ Text(`Custom Local: ${this.customCounter2}`).fontColor('#ff6b6565').margin({ left: -110, top: 12 })
579
+ }
580
+ }
581
+ }
582
+ }
583
+
584
+ @Entry
585
+ @Component
586
+ struct MainProgram {
587
+ @State mainCounter: number = 10;
588
+
589
+ build() {
590
+ Column() {
591
+ Row() {
592
+ Column() {
593
+ // customCounter必须从父组件初始化,因为MyComponent的customCounter成员变量缺少本地初始化;此处,customCounter2可以不做初始化
594
+ MyComponent({ customCounter: this.mainCounter })
595
+ // customCounter2也可以从父组件初始化,父组件初始化的值会覆盖子组件customCounter2的本地初始化的值
596
+ MyComponent({ customCounter: this.mainCounter, customCounter2: this.mainCounter })
597
+ }
598
+ }
599
+
600
+ Row() {
601
+ Column() {
602
+ Button('Click to change number')
603
+ .width(288)
604
+ .height(40)
605
+ .margin({ left: 30, top: 12 })
606
+ .fontColor('#FFFFFF')
607
+ .onClick(() => {
608
+ this.mainCounter++;
609
+ })
610
+ }
611
+ }
612
+ }
613
+ }
614
+ }
615
+ ```
616
+
617
+ ![@Prop本地初始化不和父组件同步效果图](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/e0/v3/oBJkydByRu2-8HFCeB_lrg/zh-cn_image_0000002566707935.gif)
618
+
619
+ ### @Prop嵌套场景
620
+
621
+ 在嵌套场景下,每一层都要用@Observed装饰,且每一层都要被@Prop接收,这样才能观察到嵌套场景。
622
+
623
+ ```TypeScript
624
+ // 以下是嵌套类对象的数据结构。
625
+ @Observed
626
+ class Son {
627
+ public title: string;
628
+
629
+ constructor(title: string) {
630
+ this.title = title;
631
+ }
632
+ }
633
+
634
+ @Observed
635
+ class Father {
636
+ public name: string;
637
+ public son: Son;
638
+
639
+ constructor(name: string, son: Son) {
640
+ this.name = name;
641
+ this.son = son;
642
+ }
643
+ }
644
+ ```
645
+
646
+ 以下组件层次结构展示了@Prop嵌套场景的数据结构。
647
+
648
+ ```TypeScript
649
+ @Entry
650
+ @Component
651
+ struct Person {
652
+ @State person: Father = new Father('Hello', new Son('world'));
653
+
654
+ build() {
655
+ Column() {
656
+ Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
657
+ Button('change Father name')
658
+ .width(312)
659
+ .height(40)
660
+ .margin(12)
661
+ .fontColor('#FFFFFF')
662
+ .onClick(() => {
663
+ this.person.name = 'Hi';
664
+ })
665
+ Button('change Son title')
666
+ .width(312)
667
+ .height(40)
668
+ .margin(12)
669
+ .fontColor('#FFFFFF')
670
+ .onClick(() => {
671
+ // person被@State装饰,@State无法观测到嵌套类型的变化,直接点击该按钮,此时title已经发生变化,但是无法被观测到。
672
+ this.person.son.title = 'ArkUI';
673
+ })
674
+ Text(this.person.name)
675
+ .fontSize(16)
676
+ .margin(12)
677
+ .width(312)
678
+ .height(40)
679
+ .backgroundColor('#ededed')
680
+ .borderRadius(20)
681
+ .textAlign(TextAlign.Center)
682
+ .fontColor('#e6000000')
683
+ .onClick(() => {
684
+ // 点击该按钮,此次变化会被观测到,同时能够观察到Button('change Son title')点击后的效果。
685
+ this.person.name = 'Bye';
686
+ })
687
+ Text(this.person.son.title)
688
+ .fontSize(16)
689
+ .margin(12)
690
+ .width(312)
691
+ .height(40)
692
+ .backgroundColor('#ededed')
693
+ .borderRadius(20)
694
+ .textAlign(TextAlign.Center)
695
+ .onClick(() => {
696
+ this.person.son.title = 'openHarmony';
697
+ })
698
+ Child({ child: this.person.son })
699
+ }
700
+ }
701
+ }
702
+ }
703
+
704
+
705
+ @Component
706
+ struct Child {
707
+ @Prop child: Son = new Son('');
708
+
709
+ build() {
710
+ Column() {
711
+ Text(this.child.title)
712
+ .fontSize(16)
713
+ .margin(12)
714
+ .width(312)
715
+ .height(40)
716
+ .backgroundColor('#ededed')
717
+ .borderRadius(20)
718
+ .textAlign(TextAlign.Center)
719
+ .onClick(() => {
720
+ this.child.title = 'Bye Bye';
721
+ })
722
+ }
723
+ }
724
+ }
725
+ ```
726
+
727
+ ![@Prop嵌套场景效果图](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/7d/v3/oJbREGPIQyqm9wKzW0G1Tw/zh-cn_image_0000002535788140.gif)
728
+
729
+ ### 装饰Array类型变量
730
+
731
+ 在下面的示例中,message类型为number[],点击Button改变message的值,视图会随之刷新。
732
+
733
+ ```TypeScript
734
+ @Entry
735
+ @Component
736
+ struct Index {
737
+ @State message: number[] = [0, 1, 2, 3];
738
+
739
+ build() {
740
+ Column() {
741
+ Child({ message: this.message })
742
+ }
743
+ }
744
+ }
745
+
746
+ @Component
747
+ struct Child {
748
+ @Prop message: number[] = [0, 1, 2, 3];
749
+
750
+ build() {
751
+ Row() {
752
+ Column() {
753
+ ForEach(this.message, (item: number) => {
754
+ Text(`${item}`)
755
+ .fontSize(20)
756
+ .margin(10)
757
+ })
758
+ // 新增数组元素,触发UI刷新
759
+ Button('Push element')
760
+ .onClick(() => {
761
+ this.message.push(4);
762
+ })
763
+ .width(300)
764
+ .margin(10)
765
+ // 删除数组元素,触发UI刷新
766
+ Button('Pop element')
767
+ .onClick(() => {
768
+ this.message.pop();
769
+ })
770
+ .width(300)
771
+ .margin(10)
772
+ // 对数组整体重新赋值,触发UI刷新
773
+ Button('Reset array')
774
+ .onClick(() => {
775
+ this.message = [9, 8, 7, 6];
776
+ })
777
+ .width(300)
778
+ .margin(10)
779
+ // 更新数组元素,触发UI刷新
780
+ Button('Modify element[0]')
781
+ .onClick(() => {
782
+ this.message[0] = 10;
783
+ })
784
+ .width(300)
785
+ .margin(10)
786
+ }
787
+ .width('100%')
788
+ }
789
+ .height('100%')
790
+ }
791
+ }
792
+ ```
793
+
794
+ ### 装饰Map类型变量
795
+
796
+ > **说明:**
797
+ >
798
+ > 从API version 11开始,@Prop支持Map类型。
799
+
800
+ 在下面的示例中,value类型为Map&lt;number, string&gt;,点击Button改变value的值,视图会随之刷新。
801
+
802
+ ```TypeScript
803
+ @Component
804
+ struct Child {
805
+ @Prop value: Map<number, string> = new Map([[0, 'a'], [1, 'b'], [3, 'c']]);
806
+
807
+ build() {
808
+ Column() {
809
+ ForEach(Array.from(this.value.entries()), (item: [number, string]) => {
810
+ Text(`${item[0]}`).fontSize(30)
811
+ Text(`${item[1]}`).fontSize(30)
812
+ Divider()
813
+ })
814
+ Button('child init map').onClick(() => {
815
+ this.value = new Map([[0, 'a'], [1, 'b'], [3, 'c']]);
816
+ })
817
+ Button('child set new one').onClick(() => {
818
+ this.value.set(4, 'd');
819
+ })
820
+ Button('child clear').onClick(() => {
821
+ this.value.clear();
822
+ })
823
+ Button('child replace the first one').onClick(() => {
824
+ this.value.set(0, 'aa');
825
+ })
826
+ Button('child delete the first one').onClick(() => {
827
+ this.value.delete(0);
828
+ })
829
+ }
830
+ }
831
+ }
832
+
833
+
834
+ @Entry
835
+ @Component
836
+ struct MapSample {
837
+ @State message: Map<number, string> = new Map([[0, 'a'], [1, 'b'], [3, 'c']]);
838
+
839
+ build() {
840
+ Row() {
841
+ Column() {
842
+ Child({ value: this.message })
843
+ }
844
+ .width('100%')
845
+ }
846
+ .height('100%')
847
+ }
848
+ }
849
+ ```
850
+
851
+ ### 装饰Set类型变量
852
+
853
+ > **说明:**
854
+ >
855
+ > 从API version 11开始,@Prop支持Set类型。
856
+
857
+ 在下面的示例中,message类型为Set&lt;number&gt;,点击Button改变message的值,视图会随之刷新。
858
+
859
+ ```TypeScript
860
+ @Component
861
+ struct Child {
862
+ @Prop message: Set<number> = new Set([0, 1, 2, 3, 4]);
863
+
864
+ build() {
865
+ Column() {
866
+ ForEach(Array.from(this.message.entries()), (item: [number, number]) => {
867
+ Text(`${item[0]}`).fontSize(30)
868
+ Divider()
869
+ })
870
+ Button('init set').onClick(() => {
871
+ this.message = new Set([0, 1, 2, 3, 4]);
872
+ })
873
+ Button('set new one').onClick(() => {
874
+ this.message.add(5);
875
+ })
876
+ Button('clear').onClick(() => {
877
+ this.message.clear();
878
+ })
879
+ Button('delete the first one').onClick(() => {
880
+ this.message.delete(0);
881
+ })
882
+ }
883
+ .width('100%')
884
+ }
885
+ }
886
+
887
+
888
+ @Entry
889
+ @Component
890
+ struct SetSample {
891
+ @State message: Set<number> = new Set([0, 1, 2, 3, 4]);
892
+
893
+ build() {
894
+ Row() {
895
+ Column() {
896
+ Child({ message: this.message })
897
+ }
898
+ .width('100%')
899
+ }
900
+ .height('100%')
901
+ }
902
+ }
903
+ ```
904
+
905
+ ### 装饰Date类型变量
906
+
907
+ 在下面的示例中,selectedDate类型为Date,点击Button改变Date的值,视图会随之刷新。
908
+
909
+ ```TypeScript
910
+ @Component
911
+ struct DateComponent {
912
+ @Prop selectedDate: Date = new Date('');
913
+
914
+ build() {
915
+ Column() {
916
+ Button('child update the new date')
917
+ .margin(10)
918
+ .onClick(() => {
919
+ this.selectedDate = new Date('2023-09-09');
920
+ })
921
+ Button(`child increase the year by 1`).onClick(() => {
922
+ this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1);
923
+ })
924
+ DatePicker({
925
+ start: new Date('1970-1-1'),
926
+ end: new Date('2100-1-1'),
927
+ selected: this.selectedDate
928
+ })
929
+ }
930
+ }
931
+ }
932
+
933
+ @Entry
934
+ @Component
935
+ struct ParentComponent {
936
+ @State parentSelectedDate: Date = new Date('2021-08-08');
937
+
938
+ build() {
939
+ Column() {
940
+ Button('parent update the new date')
941
+ .margin(10)
942
+ .onClick(() => {
943
+ this.parentSelectedDate = new Date('2023-07-07');
944
+ })
945
+ Button('parent increase the day by 1')
946
+ .margin(10)
947
+ .onClick(() => {
948
+ this.parentSelectedDate.setDate(this.parentSelectedDate.getDate() + 1);
949
+ })
950
+ DatePicker({
951
+ start: new Date('1970-1-1'),
952
+ end: new Date('2100-1-1'),
953
+ selected: this.parentSelectedDate
954
+ })
955
+
956
+ DateComponent({ selectedDate: this.parentSelectedDate })
957
+ }
958
+ }
959
+ }
960
+ ```
961
+
962
+ ### Prop支持联合类型实例
963
+
964
+ @Prop支持联合类型和undefined和null,在下面的示例中,animal类型为Animals | undefined,点击父组件Zoo中的Button改变animal的属性或者类型,Child中也会对应刷新。
965
+
966
+ ```TypeScript
967
+ import { hilog } from '@kit.PerformanceAnalysisKit';
968
+
969
+ const DOMAIN = 0x0001;
970
+ const TAG: string = '[SampleProp]';
971
+
972
+ class Animals {
973
+ public name: string;
974
+
975
+ constructor(name: string) {
976
+ this.name = name;
977
+ }
978
+ }
979
+
980
+ @Component
981
+ struct Child {
982
+ @Prop animal: Animals | undefined;
983
+
984
+ build() {
985
+ Column() {
986
+ Text(`Child's animal is ${this.animal instanceof Animals ? this.animal.name : 'undefined'}`).fontSize(30)
987
+
988
+ Button('Child change animals into tigers')
989
+ .onClick(() => {
990
+ // 赋值为Animals的实例
991
+ this.animal = new Animals('Tiger');
992
+ })
993
+
994
+ Button('Child change animal to undefined')
995
+ .onClick(() => {
996
+ // 赋值为undefined
997
+ this.animal = undefined;
998
+ })
999
+
1000
+ }.width('100%')
1001
+ }
1002
+ }
1003
+
1004
+ @Entry
1005
+ @Component
1006
+ struct Zoo {
1007
+ @State animal: Animals | undefined = new Animals('lion');
1008
+
1009
+ build() {
1010
+ Column() {
1011
+ Text(`Parents' animals are ${this.animal instanceof Animals ? this.animal.name : 'undefined'}`).fontSize(30)
1012
+
1013
+ Child({ animal: this.animal })
1014
+
1015
+ Button('Parents change animals into dogs')
1016
+ .onClick(() => {
1017
+ // 判断animal的类型,做属性的更新
1018
+ if (this.animal instanceof Animals) {
1019
+ this.animal.name = 'Dog';
1020
+ } else {
1021
+ hilog.info(DOMAIN, TAG, 'num is undefined, cannot change property');
1022
+ }
1023
+ })
1024
+
1025
+ Button('Parents change animal to undefined')
1026
+ .onClick(() => {
1027
+ // 赋值为undefined
1028
+ this.animal = undefined;
1029
+ })
1030
+ }
1031
+ }
1032
+ }
1033
+ ```