diff --git a/zh-cn/application-dev/quick-start/Readme-CN.md b/zh-cn/application-dev/quick-start/Readme-CN.md
index 8b6b2da8d07c319f0c18ef28ba9506fce0dbe6e8..c377e32c471a38383c8ef962c3a19eb8726981f1 100644
--- a/zh-cn/application-dev/quick-start/Readme-CN.md
+++ b/zh-cn/application-dev/quick-start/Readme-CN.md
@@ -41,12 +41,37 @@
- [资源分类与访问](resource-categories-and-access.md)
- 学习ArkTS语言
- [初识ArkTS语言](arkts-get-started.md)
- - ArkTS语法(声明式UI)
- - [基本UI描述](arkts-basic-ui-description.md)
- - 状态管理
- - [基本概念](arkts-state-mgmt-concepts.md)
- - [页面级变量的状态管理](arkts-state-mgmt-page-level.md)
- - [应用级变量的状态管理](arkts-state-mgmt-application-level.md)
- - [动态构建UI元素](arkts-dynamic-ui-elememt-building.md)
- - [渲染控制](arkts-rendering-control.md)
- - [使用限制与扩展](arkts-restrictions-and-extensions.md)
\ No newline at end of file
+ - 基本语法
+ - [基本语法概述](arkts-basic-syntax-overview.md)
+ - [声明式UI描述](arkts-declarative-ui-description.md)
+ - 自定义组件
+ - [创建自定义组件](arkts-create-custom-components.md)
+ - [页面和自定义组件生命周期](arkts-page-custom-components-lifecycle.md)
+ - [\@Builder:自定义构建函数](arkts-builder.md)
+ - [\@BuilderParam:引用\@Builder函数](arkts-builderparam.md)
+ - [\@Styles:定义组件重用样式](arkts-style.md)
+ - [\@Extend:定义扩展组件样式](arkts-extend.md)
+ - [stateStyles:多态样式](arkts-statestyles.md)
+ - 状态管理
+ - [状态管理概述](arkts-state-management-overview.md)
+ - 管理组件拥有的状态
+ - [\@State:组件内状态](arkts-state.md)
+ - [\@Prop:父子单向同步](arkts-prop.md)
+ - [\@Link:父子双向同步](arkts-link.md)
+ - [\@Provide和\@Consume:与后代组件双向同步](arkts-provide-and-consume.md)
+ - [\@Observed和\@ObjectLink:嵌套类对象属性变化](arkts-observed-and-objectlink.md)
+ - 管理应用拥有的状态
+ - [管理应用拥有的状态概述](arkts-application-state-management-overview.md)
+ - [LocalStorage:页面级UI状态存储](arkts-localstorage.md)
+ - [AppStorage:应用全局的UI状态存储](arkts-appstorage.md)
+ - [PersistentStorage:持久化存储UI状态](arkts-persiststorage.md)
+ - [Environment:设备环境查询](arkts-environment.md)
+ - 其他状态管理
+ - [其他状态管理概述](arkts-other-state-mgmt-functions-overview.md)
+ - [\@Watch:状态变量更改通知](arkts-watch.md)
+ - [$$语法:内置组件双向同步](arkts-two-way-sync.md)
+ - 渲染控制
+ - [渲染控制概述](arkts-rendering-control-overview.md)
+ - [if/else:条件渲染](arkts-rendering-control-ifelse.md)
+ - [ForEach:循环渲染](arkts-rendering-control-foreach.md)
+ - [LazyForEach:数据懒加载](arkts-rendering-control-lazyforeach.md)
diff --git a/zh-cn/application-dev/quick-start/arkts-application-state-management-overview.md b/zh-cn/application-dev/quick-start/arkts-application-state-management-overview.md
new file mode 100644
index 0000000000000000000000000000000000000000..f3bb0e45598c3aa59ae20b521eec25ba5cff8375
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-application-state-management-overview.md
@@ -0,0 +1,13 @@
+# 管理应用拥有的状态概述
+
+
+上一个章节中介绍的装饰器仅能在页面内,即一个组件树上共享状态变量。如果开发者要实现应用级的,或者多个页面的状态数据共享,就需要用到应用级别的状态管理的概念。ArkTS根据不同特性,提供了多种应用状态管理的能力:
+
+
+- [LocalStorage](arkts-localstorage.md):页面级UI状态存储,通常用于[UIAbility](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-app-ability-uiAbility.md)内、页面间的状态共享。
+
+- [AppStorage](arkts-appstorage.md):特殊的单例LocalStorage对象,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储;
+
+- [PersistentStorage](arkts-persiststorage.md):持久化存储UI状态,通常和AppStorage配合使用,选择AppStorage存储的数据写入磁盘,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同;
+
+- [Environment](arkts-environment.md):应用程序运行的设备的环境参数,环境参数会同步到AppStorage中,可以和AppStorage搭配使用。
diff --git a/zh-cn/application-dev/quick-start/arkts-appstorage.md b/zh-cn/application-dev/quick-start/arkts-appstorage.md
new file mode 100644
index 0000000000000000000000000000000000000000..8c8e3cc9f4bfef2ce339f43045ca7040da9676f3
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-appstorage.md
@@ -0,0 +1,203 @@
+# AppStorage:应用全局的UI状态存储
+
+
+AppStorage是应用全局的UI状态存储,是和应用的进程绑定的,由UI框架在应用程序启动时创建,为应用程序UI状态属性提供中央存储。
+
+
+和LocalStorage不同的是,LocalStorage是页面级的,通常应用于页面内的数据共享。而对于AppStorage,是应用级的全局状态共享。AppStorage还相当于整个应用的“中枢”,[持久化数据PersistentStorage](arkts-persiststorage.md)和[环境变量Environment](arkts-environment.md)都是通过和AppStorage中转,才可以和UI回交互。
+
+
+本文仅介绍AppStorage使用场景和相关的装饰器:\@StorageProp和\@StorageLink。
+
+
+## 概述
+
+AppStorage是LocalStorage是在应用启动的时候会被创建的单例。它的目的是为了提供应用状态数据的中心存储,这些状态数据在应用级别都是可访问的。AppStorage将在应用运行过程保留其属性。属性通过唯一的键字符串值访问。
+
+AppStorage可以和UI组件同步,且可以在应用业务逻辑中被访问。
+
+AppStorage中的属性可以被双向同步,数据可以是存在于本地或远程设备上,并具有不同的功能,比如数据持久化(详见[PersistentStorage](arkts-persiststorage.md))。这些数据是通过业务逻辑中实现,与UI解耦,如果希望这些数据在UI中使用,需要用到[@StorageProp](#storageprop)和[@StorageLink](#storagelink)。
+
+
+## \@StorageProp
+
+在上文中已经提到,如果要建立AppStorage和自定义组件的联系,需要使用\@StorageProp和\@StorageLink装饰器。使用\@StorageProp(key)/\@StorageLink(key)装饰组件内的变量,key标识了AppStorage的属性。
+
+当自定义组件初始化的时候,\@StorageProp(key)/\@StorageLink(key)装饰的变量会通过给定的key,绑定在AppStorage对应是属性,完成初始化。本地初始化是必要的,因为无法保证AppStorage一定存在给定的key,这取决于应用逻辑,是否在组件初始化之前在AppStorage实例中存入对应的属性。
+
+
+\@StorageProp(key)是和AppStorage中key对应的属性建立单向数据同步,我们允许本地改变的发生,但是对于\@StorageProp,本地的修改永远不会同步回AppStorage中,相反,如果AppStorage给定key的属性发生改变,改变会被同步给\@StorageProp,并覆盖掉本地的修改。
+
+
+### 装饰器使用规则说明
+
+| \@StorageProp变量装饰器 | 说明 |
+| ------------------ | ---------------------------------------- |
+| 装饰器参数 | key:常量字符串,必填(字符串需要有引号)。 |
+| 允许装饰的变量类型 | Object class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考[观察变化和行为表现](#观察变化和行为表现)。
类型必须被指定,且必须和LocalStorage中对应属性相同。不支持any,不允许使用undefined和null。 |
+| 同步类型 | 单向同步:从AppStorage的对应属性到组件的状态变量。
组件本地的修改是允许的,但是AppStorage中给定的属性一旦发生变化,将覆盖本地的修改。 |
+| 被装饰变量的初始值 | 必须指定,如果AppStorage实例中不存在属性,则作为初始化默认值,并存入AppStorage中。 |
+
+
+### 变量的传递/访问规则说明
+
+| 传递/访问 | 说明 |
+| ---------- | ---------------------------------------- |
+| 从父节点初始化和更新 | 禁止,\@StorageProp不支持从父节点初始化,只能AppStorage中key对应的属性初始化,如果没有对应key的话,将使用本地默认值初始化 |
+| 初始化子节点 | 支持,可用于初始化\@State、\@Link、\@Prop、\@Provide。 |
+| 是否支持组件外访问 | 否。 |
+
+
+ **图1** \@StorageProp初始化规则图示
+
+
+
+
+
+### 观察变化和行为表现
+
+**观察变化**
+
+
+- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
+
+- 当装饰的数据类型为class或者Object时,可以观察到赋值和属性赋值的变化,即Object.keys(observedObject)返回的所有属性。
+
+- 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化。
+
+
+**框架行为**
+
+
+- 当\@StorageProp(key)装饰的数值改变被观察到时,修改不会被同步回AppStorage对应属性键值key的属性中。
+
+- 当前\@StorageProp(key)单向绑定的数据会被修改,即仅限于当前组件的私有成员变量改变,其他的绑定该key的数据不会同步改变。
+
+- 当\@StorageProp(key)装饰的数据本身是状态变量,它的改变虽然不会同步回AppStorage中,但是会引起所属的自定义组件的重新渲染。
+
+- 当AppStorage中key对应的属性发生改变时,会同步给所有\@StorageProp(key)装饰的数据,\@StorageProp(key)本地的修改将被覆盖。
+
+
+## \@StorageLink
+
+\@StorageLink(key)是和AppStorage中key对应的属性建立双向数据同步:
+
+1. 本地修改发生,该修改会被回AppStorage中;
+
+2. AppStorage中的修改发生后,该修改会被同步到所有绑定AppStorage对应key的属性上,包括单向(\@StorageProp和通过Prop创建的单向绑定变量)、双向(\@StorageLink和通过Link创建的双向绑定变量)变量和其他实例(比如PersistentStorage)。
+
+
+### 装饰器使用规则说明
+
+| \@StorageLink变量装饰器 | 说明 |
+| ------------------ | ---------------------------------------- |
+| 装饰器参数 | key:常量字符串,必填(字符串需要有引号)。 |
+| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考[观察变化和行为表现](#观察变化和行为表现)。
类型必须被指定,且必须和AppStorage中对应属性相同。不支持any,不允许使用undefined和null。 |
+| 同步类型 | 双向同步:从AppStorage的对应属性到自定义组件,从自定义组件到AppStorage对应属性。 |
+| 被装饰变量的初始值 | 必须指定,如果AppStorage实例中不存在属性,则作为初始化默认值,并存入AppStorage中。 |
+
+
+### 变量的传递/访问规则说明
+
+| 传递/访问 | 说明 |
+| ---------- | ---------------------------------------- |
+| 从父节点初始化和更新 | 禁止。 |
+| 初始化子节点 | 支持,可用于初始化常规变量、\@State、\@Link、\@Prop、\@Provide。 |
+| 是否支持组件外访问 | 否。 |
+
+
+ **图2** \@StorageLink初始化规则图示
+
+
+
+
+
+### 观察变化和行为表现
+
+**观察变化**
+
+
+- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
+
+- 当装饰的数据类型为class或者Object时,可以观察到赋值和属性赋值的变化,即Object.keys(observedObject)返回的所有属性。
+
+- 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化。
+
+
+**框架行为**
+
+
+1. 当\@StorageLink(key)装饰的数值改变被观察到时,修改将被同步回AppStorage对应属性键值key的属性中。
+
+2. AppStorage中属性键值key对应的数据一旦改变,属性键值key绑定的所有的数据(包括双向\@StorageLink和单向\@StorageProp)都将同步修改;
+
+3. 当\@StorageLink(key)装饰的数据本身是状态变量,它的改变不仅仅会同步回AppStorage中,还会引起所属的自定义组件的重新渲染。
+
+
+## 使用场景
+
+
+### 从应用逻辑使用AppStorage和LocalStorage
+
+AppStorage是单例,它的所有API都是静态的,使用方法类似于中LocalStorage对应的非静态方法。
+
+
+```ts
+AppStorage.SetOrCreate('PropA', 47);
+
+let storage: LocalStorage = new LocalStorage({ 'PropA': 17 });
+let propA: number = AppStorage.Get('PropA') // propA in AppStorage == 47, propA in LocalStorage == 17
+var link1: SubscribedAbstractProperty = AppStorage.Link('PropA'); // link1.get() == 47
+var link2: SubscribedAbstractProperty = AppStorage.Link('PropA'); // link2.get() == 47
+var prop: SubscribedAbstractProperty = AppStorage.Prop('PropA'); // prop.get() = 47
+
+link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
+prop.set(1); // one-way sync: prop.get()=1; but link1.get() == link2.get() == 48
+link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
+
+storage.get('PropA') // == 17
+storage.set('PropA', 101);
+storage.get('PropA') // == 101
+
+AppStorage.Get('PropA') // == 49
+link1.get() // == 49
+link2.get() // == 49
+prop.get() // == 49
+```
+
+
+### 从UI内部使用AppStorage和LocalStorage
+
+\@StorageLink变量装饰器与AppStorage配合使用,正如\@LocalStorageLink与LocalStorage配合使用一样。此装饰器使用AppStorage中的属性创建双向数据同步。
+
+
+```ts
+AppStorage.SetOrCreate('PropA', 47);
+let storage = new LocalStorage({ 'PropA': 48 });
+
+@Entry(storage)
+@Component
+struct CompA {
+ @StorageLink('PropA') storLink: number = 1;
+ @LocalStorageLink('PropA') localStorLink: number = 1;
+
+ build() {
+ Column({ space: 20 }) {
+ Text(`From AppStorage ${this.storLink}`)
+ .onClick(() => this.storLink += 1)
+
+ Text(`From LocalStorage ${this.localStorLink}`)
+ .onClick(() => this.localStorLink += 1)
+ }
+ }
+}
+```
+
+
+## 限制条件
+
+AppStorage与[PersistentStorage](arkts-persiststorage.md)以及[Environment](arkts-environment.md)配合使用时,需要注意以下几点:
+
+- 在AppStorage中创建属性后,调用PersistentStorage.PersistProp()接口时,会使用在AppStorage中已经存在的值,并覆盖PersistentStorage中的同名属性,所以建议要使用相反的调用顺序,反例可见[在PersistentStorage之前访问AppStorage中的属性](arkts-persiststorage.md#在persistentstorage之前访问appstorage中的属性);
+
+- 如果在AppStorage中已经创建属性后,再调用Environment.EnvProp()创建同名的属性,会调用失败。因为AppStorage已经有同名属性,Environment环境变量不会再写入AppStorage中,所以建议AppStorage中属性不要使用Environment预置环境变量名。
diff --git a/zh-cn/application-dev/quick-start/arkts-basic-syntax-overview.md b/zh-cn/application-dev/quick-start/arkts-basic-syntax-overview.md
new file mode 100644
index 0000000000000000000000000000000000000000..7a7404987fb97f7e471576b801b266be96688815
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-basic-syntax-overview.md
@@ -0,0 +1,40 @@
+# 基本语法概述
+
+
+在初步了解了ArkTS语言之后,我们以一个具体的示例来说明ArkTS的基本组成。如下图所示,当开发者点击按钮时,文本内容从“Hello World”变为“Hello ArkUI”。
+
+
+ **图1** 示例效果图
+
+
+
+
+本示例中,ArkTS的基本组成如下所示。
+
+
+ **图2** ArkTS的基本组成
+
+
+
+
+- 装饰器: 用于装饰类、结构、方法以及变量,并赋予其特殊的含义。如上述示例中\@Entry、\@Component和\@State都是装饰器,\@Component表示自定义组件,\@Entry表示该自定义组件为入口组件,\@State表示组件中的状态变量,状态变量变化会触发UI刷新。
+
+- [UI描述](arkts-declarative-ui-description.md):以声明式的方式来描述UI的结构,例如build()方法中的代码块。
+
+- [自定义组件](arkts-create-custom-components.md):可复用的UI单元,可组合其他组件,如上述被\@Component装饰的struct Hello。
+
+- 系统组件:ArkUI框架中默认内置的基础和容器组件,可直接被开发者调用,比如示例中的Column 、 Text 、 Divider 、 Button。
+
+- 属性方法:组件可以通过链式调用配置多项属性,如fontSize()、width()、height()、color()等。
+
+- 事件方法:组件可以通过链式调用设置多个事件的响应逻辑,如跟随在Button后面的onClick()。
+
+
+除此之外,ArkTS扩展了多种语法范式来使开发更加便捷:
+
+
+- [@Builder](arkts-builder.md)/[@BuilderParam](arkts-builderparam.md):特殊的封装UI描述的方法,细粒度的封装和复用UI描述。
+
+- [@Extend](arkts-extend.md)/[@Style](arkts-style.md):扩展内置组件和封装属性样式,更灵活地组合内置组件。
+
+- [stateStyles](arkts-statestyles.md):多态样式,可以依据组件的内部状态的不同,设置不同样式。
diff --git a/zh-cn/application-dev/quick-start/arkts-basic-ui-description.md b/zh-cn/application-dev/quick-start/arkts-basic-ui-description.md
deleted file mode 100644
index c705d35f5cca6c34cd7d52986153663246946f67..0000000000000000000000000000000000000000
--- a/zh-cn/application-dev/quick-start/arkts-basic-ui-description.md
+++ /dev/null
@@ -1,203 +0,0 @@
-# 基本UI描述
-
-ArkTS通过装饰器@Component和@Entry装饰struct关键字声明的数据结构,构成一个自定义组件。自定义组件中提供了一个build函数,开发者需在该函数内以链式调用的方式进行基本的UI描述,UI描述的方法请参考[UI描述规范](#ui描述规范)。
-
-## 基本概念
-
-- struct:自定义组件可以基于struct实现,不能有继承关系,对于struct的实例化,可以省略new。
-
-- 装饰器:装饰器给被装饰的对象赋予某一种能力,其不仅可以装饰类或结构体,还可以装饰类的属性。多个装饰器可以叠加到目标元素上,定义在同一行中或者分开多行,推荐分开多行定义。
-
- ```ts
- @Entry
- @Component
- struct MyComponent {
- }
- ```
-
-- build函数:自定义组件必须定义build函数,并且禁止自定义构造函数。build函数满足Builder构造器接口定义,用于定义组件的声明式UI描述。
-
- ```ts
- interface Builder {
- build: () => void
- }
- ```
-
-- @Component:装饰struct,结构体在装饰后具有基于组件的能力,需要实现build方法来创建UI。
-
-- @Entry: 装饰struct,组件被装饰后作为页面的入口,页面加载时将被渲染显示。
-
-- @Preview:装饰struct, 用@Preview装饰的自定义组件可以在DevEco Studio的预览器上进行实时预览,加载页面时,将创建并显示@Preview装饰的自定义组件。
-
- > **说明:** 在单个源文件中,最多可以使用10个@Preview装饰自定义组件,更多说明请参考[查看ArkTS组件预览效果](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-previewing-app-service-0000001218760596#section146052489820)。
-
-- 链式调用:以 "." 链式调用的方式配置UI组件的属性方法、事件方法等。
-
-## UI描述规范
-
-### 无参数构造配置
-
-如果组件的接口定义中不包含必选构造参数,组件后面的“()”中不需要配置任何内容。例如,Divider组件不包含构造参数:
-
-```ts
-Column() {
- Text('item 1')
- Divider()
- Text('item 2')
-}
-```
-
-### 有参数构造配置
-
-如果组件的接口定义中包含构造参数,则在组件后面的“()”中可配置相应参数,参数可以使用常量进行赋值。
-
-例如:
-
-- Image组件的必选参数src:
-
- ```ts
- Image('https://xyz/test.jpg')
- ```
-
-- Text组件的参数content,该参数非必选,即配置或不配置均可:
-
- ```ts
- Text('test')
- ```
-
-变量或表达式也可以用于参数赋值,其中表达式返回的结果类型必须满足参数类型要求,变量的定义详见[页面级变量的状态管理](arkts-state-mgmt-page-level.md)与[应用级变量的状态管理](arkts-state-mgmt-application-level.md)。例如,设置变量或表达式来构造Image和Text组件的参数:
-
-```ts
-Image(this.imagePath)
-Image('https://' + this.imageUrl)
-Text(`count: ${this.count}`)
-```
-
-### 属性配置
-
-使用属性方法配置组件的属性,属性方法紧随组件,并用"."运算符连接。
-
-- 配置Text组件的字体大小属性:
-
- ```ts
- Text('test')
- .fontSize(12)
- ```
-
-- 使用"."运算符进行链式调用并同时配置组件的多个属性,如下所示:
-
- ```ts
- Image('test.jpg')
- .alt('error.jpg')
- .width(100)
- .height(100)
- ```
-
-- 除了直接传递常量参数外,还可以传递变量或表达式,如下所示:
-
- ```ts
- Text('hello')
- .fontSize(this.size)
- Image('test.jpg')
- .width(this.count % 2 === 0 ? 100 : 200)
- .height(this.offset + 100)
- ```
-
-- 对于系统内置组件,框架还为其属性预定义了一些[枚举类型](../reference/arkui-ts/ts-appendix-enums.md)供开发人员调用,枚举类型可以作为参数传递,且必须满足参数类型要求。例如,可以按以下方式配置Text组件的颜色和字体属性:
-
- ```ts
- Text('hello')
- .fontSize(20)
- .fontColor(Color.Red)
- .fontWeight(FontWeight.Bold)
- ```
-
-### 事件配置
-
-通过事件方法可以配置组件支持的事件,事件方法紧随组件,并用"."运算符连接。
-
-- 使用lambda表达式配置组件的事件方法:
-
- ```ts
- Button('add counter')
- .onClick(() => {
- this.counter += 2
- })
- ```
-
-- 使用匿名函数表达式配置组件的事件方法,要求使用bind,以确保函数体中的this引用包含的组件:
-
- ```ts
- Button('add counter')
- .onClick(function () {
- this.counter += 2
- }.bind(this))
- ```
-
-- 使用组件的成员函数配置组件的事件方法:
-
- ```ts
- myClickHandler(): void {
- this.counter += 2
- }
-
- ...
-
- Button('add counter')
- .onClick(this.myClickHandler.bind(this))
- ```
-
-### 子组件配置
-
-对于支持子组件配置的组件,例如容器组件,在"{ ... }"里为组件添加子组件的UI描述。Column、Row、Stack、Grid、List等组件都是容器组件。
-
-- 以下是简单的Column示例:
-
- ```ts
- Column() {
- Text('Hello')
- .fontSize(100)
- Divider()
- Text(this.myText)
- .fontSize(100)
- .fontColor(Color.Red)
- }
- ```
-
-- 容器组件之间也可以互相嵌套,实现相对复杂的多级嵌套效果:
-
- ```ts
- Column() {
- Row() {
- Image('test1.jpg')
- .width(100)
- .height(100)
- Button('click +1')
- .onClick(() => {
- console.info('+1 clicked!')
- })
- }
-
- Divider()
- Row() {
- Image('test2.jpg')
- .width(100)
- .height(100)
- Button('click +2')
- .onClick(() => {
- console.info('+2 clicked!')
- })
- }
-
- Divider()
- Row() {
- Image('test3.jpg')
- .width(100)
- .height(100)
- Button('click +3')
- .onClick(() => {
- console.info('+3 clicked!')
- })
- }
- }
- ```
\ No newline at end of file
diff --git a/zh-cn/application-dev/quick-start/arkts-builder.md b/zh-cn/application-dev/quick-start/arkts-builder.md
new file mode 100644
index 0000000000000000000000000000000000000000..0de195ec6e80014163e1a76ca973e6563aea79ce
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-builder.md
@@ -0,0 +1,130 @@
+# \@Builder:自定义构建函数
+
+
+前面章节介绍了如何创建一个自定义组件。该自定义组件内部UI结构固定,仅与使用方进行数据传递。ArkUI还提供了一种更轻量的UI元素复用机制\@Builder,\@Builder所装饰的函数遵循build()函数语法规则,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。
+
+
+为了简化语言,我们将\@Builder装饰的函数也称为“自定义构建函数”。
+
+
+> **说明:**
+>
+> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+
+## 装饰器使用说明
+
+
+### 自定义组件内自定义构建函数
+
+定义的语法:
+
+
+```ts
+@Builder myBuilderFunction({ ... })
+```
+
+使用方法:
+
+
+```ts
+this.myBuilderFunction({ ... })
+```
+
+- 允许在自定义组件内定义一个或多个自定义构建函数,该函数被认为是该组件的私有、特殊类型的成员函数。
+
+- 自定义构建函数可以在所属组件的build方法和其他自定义构建函数中调用,但不允许在组件外调用。
+
+- 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不是参数传递。
+
+
+### 全局自定义构建函数
+
+定义的语法:
+
+
+```ts
+@Builder function MyGlobalBuilderFunction({ ... })
+```
+
+使用方法:
+
+
+```ts
+MyGlobalBuilderFunction()
+```
+
+
+- 全局的自定义构建函数可以被整个应用获取,不允许使用this和bind方法。
+
+- 如果不涉及组件状态变化,建议使用全局的自定义构建方法。
+
+
+## 参数传递规则
+
+自定义构建函数的参数传递有[按值传递](#按值传递参数)和[按引用传递](#按引用传递参数)两种,均需遵守以下规则:
+
+- 参数的类型必须与参数声明的类型一致,不允许undefined、null和返回undefined、null的表达式。
+
+- 在自定义构建函数内部,不允许改变参数值。如果需要改变参数值,且同步回调用点,建议使用[@Link](arkts-link.md)。
+
+- \@Builder内UI语法遵循[UI语法规则](arkts-create-custom-components.md#build函数)。
+
+
+### 按引用传递参数
+
+按引用传递参数时,传递的参数可为状态变量,且状态变量的改变会引起\@Builder方法内的UI刷新。ArkUI提供$$作为按引用传递参数的范式。
+
+
+```ts
+ABuilder( $$ : { paramA1: string, paramB1 : string } );
+```
+
+
+
+```ts
+@Builder function ABuilder($$: { paramA1: string }) {
+ Row() {
+ Text(`UseStateVarByReference: ${$$.paramA1} `)
+ }
+}
+@Entry
+@Component
+struct Parent {
+ @State label: string = 'Hello';
+ build() {
+ Column() {
+ // 在Parent组件中调用ABuilder的时候,将this.label引用传递给ABuilder
+ ABuilder({ paramA1: this.label })
+ Button('Click me').onClick(() => {
+ // 点击“Click me”后,UI从“Hello”刷新为“ArkUI”
+ this.label = 'ArkUI';
+ })
+ }
+ }
+}
+```
+
+
+### 按值传递参数
+
+调用\@Builder装饰的函数默认按值传递。当传递的参数为状态变量时,状态变量的改变不会引起\@Builder方法内的UI刷新。所以当使用状态变量的时候,推荐使用[按引用传递](#按引用传递参数)。
+
+
+```ts
+@Builder function ABuilder(paramA1: string) {
+ Row() {
+ Text(`UseStateVarByValue: ${paramA1} `)
+ }
+}
+@Entry
+@Component
+struct Parent {
+ label: string = 'Hello';
+ build() {
+ Column() {
+ ABuilder(this.label)
+ }
+ }
+}
+```
diff --git a/zh-cn/application-dev/quick-start/arkts-builderparam.md b/zh-cn/application-dev/quick-start/arkts-builderparam.md
new file mode 100644
index 0000000000000000000000000000000000000000..cb4b6e274ab20da9fe3493a0d1d167883648986a
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-builderparam.md
@@ -0,0 +1,210 @@
+# \@BuilderParam:引用\@Builder函数
+
+
+当开发者创建了自定义组件,并想对该组件添加特定功能时,例如在自定义组件中添加一个点击跳转操作。若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。为解决此问题,ArkUI引入了\@BuilderParam装饰器,\@BuilderParam用来装饰指向\@Builder方法的变量,开发者可在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。该装饰器用于声明任意UI描述的一个元素,类似slot占位符。
+
+
+> **说明:**
+>
+> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+
+## 装饰器使用说明
+
+
+### 初始化\@BuilderParam装饰的方法
+
+\@BuildParam装饰的方法只能被自定义构建函数(\@Builder装饰的方法)初始化。
+
+- 使用所属自定义组件的自定义构建函数或者全局的自定义构建函数,在本地初始化\@BuilderParam。
+
+ ```ts
+ @Builder function GlobalBuilder0() {}
+
+ @Component
+ struct Child {
+ @Builder doNothingBuilder() {};
+
+ @BuilderParam aBuilder0: () => void = this.doNothingBuilder;
+ @BuilderParam aBuilder1: () => void = GlobalBuilder0;
+ build(){}
+ }
+ ```
+
+- 用父组件自定义构建函数初始化子组件\@BuildParam装饰的方法。
+
+ ```ts
+ @Component
+ struct Child {
+ @BuilderParam aBuilder0: () => void;
+
+ build() {
+ Column() {
+ this.aBuilder0()
+ }
+ }
+ }
+
+ @Entry
+ @Component
+ struct Parent {
+ @Builder componentBuilder() {
+ Text(`Parent builder `)
+ }
+
+ build() {
+ Column() {
+ Child({ aBuilder0: this.componentBuilder })
+ }
+ }
+ }
+ ```
+
+
+- 需注意this指向正确。
+
+ 以下示例中,Parent组件在调用this.componentBuilder()时,this.label指向其所属组件,即“Parent”。\@Builder componentBuilder()传给子组件\@BuilderParam aBuilder0,在Child组件中调用this.aBuilder0()时,this.label指向在Child的label,即“Child”。
+
+ > **说明:**
+ >
+ > 开发者谨慎使用bind改变函数调用的上下文,可能会使this指向混乱。
+
+ ```ts
+ @Component
+ struct Child {
+ label: string = `Child`
+ @BuilderParam aBuilder0: () => void;
+
+ build() {
+ Column() {
+ this.aBuilder0()
+ }
+ }
+ }
+
+ @Entry
+ @Component
+ struct Parent {
+ label: string = `Parent`
+
+ @Builder componentBuilder() {
+ Text(`${this.label}`)
+ }
+
+ build() {
+ Column() {
+ this.componentBuilder()
+ Child({ aBuilder0: this.componentBuilder })
+ }
+ }
+ }
+ ```
+
+
+## 使用场景
+
+
+### 参数初始化组件
+
+\@BuilderParam装饰的方法可以是有参数和无参数的两种形式,需与指向的\@Builder方法类型匹配。\@BuilderParam装饰的方法类型需要和\@Builder方法类型一致。
+
+
+```ts
+@Builder function GlobalBuilder1($$ : {label: string }) {
+ Text($$.label)
+ .width(400)
+ .height(50)
+ .backgroundColor(Color.Blue)
+}
+
+@Component
+struct Child {
+ label: string = 'Child'
+ // 无参数类,指向的componentBuilder也是无参数类型
+ @BuilderParam aBuilder0: () => void;
+ // 有参数类型,指向的GlobalBuilder1也是有参数类型的方法
+ @BuilderParam aBuilder1: ($$ : { label : string}) => void;
+
+ build() {
+ Column() {
+ this.aBuilder0()
+ this.aBuilder1({label: 'global Builder label' } )
+ }
+ }
+}
+
+@Entry
+@Component
+struct Parent {
+ label: string = 'Parent'
+
+ @Builder componentBuilder() {
+ Text(`${this.label}`)
+ }
+
+ build() {
+ Column() {
+ this.componentBuilder()
+ Child({ aBuilder0: this.componentBuilder, aBuilder1: GlobalBuilder1 })
+ }
+ }
+}
+```
+
+
+### 尾随闭包初始化组件示例
+
+在自定义组件中使用\@BuilderParam装饰的属性时也可通过尾随闭包进行初始化。在初始化自定义组件时,组件后紧跟一个大括号“{}”形成尾随闭包场景。
+
+> **说明:**
+> 此场景下自定义组件内有且仅有一个使用\@BuilderParam装饰的属性。
+
+开发者可以将尾随闭包内的内容看做\@Builder装饰的函数传给\@BuilderParam。示例如下:
+
+
+```ts
+// xxx.ets
+@Component
+struct CustomContainer {
+ @Prop header: string;
+ @BuilderParam closer: () => void
+
+ build() {
+ Column() {
+ Text(this.header)
+ .fontSize(30)
+ this.closer()
+ }
+ }
+}
+
+@Builder function specificParam(label1: string, label2: string) {
+ Column() {
+ Text(label1)
+ .fontSize(30)
+ Text(label2)
+ .fontSize(30)
+ }
+}
+
+@Entry
+@Component
+struct CustomContainerUser {
+ @State text: string = 'header';
+
+ build() {
+ Column() {
+ // 创建CustomContainer,在创建CustomContainer时,通过其后紧跟一个大括号“{}”形成尾随闭包
+ // 作为传递给子组件CustomContainer @BuilderParam closer: () => void的参数
+ CustomContainer({ header: this.text }) {
+ Column() {
+ specificParam('testA', 'testB')
+ }.backgroundColor(Color.Yellow)
+ .onClick(() => {
+ this.text = 'changeHeader';
+ })
+ }
+ }
+ }
+}
+```
diff --git a/zh-cn/application-dev/quick-start/arkts-create-custom-components.md b/zh-cn/application-dev/quick-start/arkts-create-custom-components.md
new file mode 100644
index 0000000000000000000000000000000000000000..dca2351e34068df4adc7a97b29e1ad29efeab6cb
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-create-custom-components.md
@@ -0,0 +1,380 @@
+# 创建自定义组件
+
+
+在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。在进行 UI 界面开发时,通常不是简单的将系统组件进行组合使用,而是需要考虑代码可复用性、业务逻辑与UI分离,后续版本演进等因素。因此,将UI和部分业务逻辑封装成自定义组件是不可或缺的能力。
+
+
+自定义组件具有以下特点:
+
+
+- 可组合:允许开发者组合使用系统组件、及其属性和方法。
+
+- 可重用:自定义组件可以被其他组件重用,并作为不同的实例在不同的父组件或容器中使用。
+
+- 数据驱动UI更新:通过状态变量的改变,来驱动UI的刷新。
+
+
+以下示例展示了自定义组件的基本用法。
+
+
+
+```ts
+@Component
+struct HelloComponent {
+ @State message: string = 'Hello, World!';
+
+ build() {
+ // HelloComponent自定义组件组合系统组件Row和Text
+ Row() {
+ Text(this.message)
+ .onClick(() => {
+ // 状态变量message的改变驱动UI刷新,UI从'Hello, World!'刷新为'Hello, ArkUI!'
+ this.message = 'Hello, ArkUI!';
+ })
+ }
+ }
+}
+```
+
+
+HelloComponent可以在其他自定义组件中的build()函数中多次创建,实现自定义组件的重用。
+
+
+
+```ts
+@Entry
+@Component
+struct ParentComponent {
+ build() {
+ Column() {
+ Text('ArkUI message')
+ HelloComponent({ message: 'Hello, World!' });
+ Divider()
+ HelloComponent({ message: '你好!' });
+ }
+ }
+}
+```
+
+
+要完全理解上面的示例,需要了解自定义组件的以下概念定义,本文将在后面的小节中介绍:
+
+
+- [自定义组件的基本结构](#自定义组件的基本结构)
+
+- [成员函数/变量](#成员函数变量)
+
+- [自定义组件的参数规定](#自定义组件的参数规定)
+
+- [build()函数](#build函数)
+
+- [自定义组件通用样式](#自定义组件通用样式)
+
+- [自定义属性方法](#自定义属性方法)
+
+
+## 自定义组件的基本结构
+
+- struct:自定义组件基于struct实现,struct + 自定义组件名 + {...}的组合构成自定义组件,不能有继承关系。对于struct的实例化,可以省略new。
+ > **说明:**
+ >
+ > 自定义组件名、类名、函数名不能和系统组件名相同。
+
+- \@Component:\@Component装饰器仅能装饰struct关键字声明的数据结构。struct被\@Component装饰后具备组件化的能力,需要实现build方法描述UI,一个struct只能被一个\@Component装饰。
+ > **说明:**
+ >
+ > 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+ ```ts
+ @Component
+ struct MyComponent {
+ }
+ ```
+
+- build()函数:build()函数用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数。
+
+ ```ts
+ @Component
+ struct MyComponent {
+ build() {
+ }
+ }
+ ```
+
+- \@Entry:\@Entry装饰的自定义组件将作为UI页面的入口。在单个UI页面中,最多可以使用\@Entry装饰一个自定义组件。\@Entry可以接受一个可选的[LocalStorage](arkts-localstorage.md)的参数。
+
+ > **说明:**
+ >
+ > 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+ ```ts
+ @Entry
+ @Component
+ struct MyComponent {
+ }
+ ```
+
+
+## 成员函数/变量
+
+自定义组件除了必须要实现build()函数外,还可以实现其他成员函数,成员函数具有以下约束:
+
+
+- 不支持静态函数。
+
+- 成员函数的访问始终是私有的,仅能定义private。定义访问权限是可选的,其他访问权限会带来语法错误。
+
+
+自定义组件可以包含成员变量,成员变量具有以下约束:
+
+
+- 不支持静态成员变量。
+
+- 所有成员变量都是私有的,变量的访问规则与成员函数的访问规则相同。
+
+- 自定义组件的成员变量本地初始化有些是可选的,有些是必选的。具体是否需要本地初始化,是否需要从父组件通过参数传递初始化子组件的成员变量,请参考[状态管理](arkts-state-management-overview.md)。
+
+
+## 自定义组件的参数规定
+
+从上文的示例中,我们已经了解到,可以在build方法或者[@Builder](arkts-builder.md)装饰的函数里创建自定义组件,在创建的过程中,参数可以被提供给组件。
+
+
+```ts
+@Component
+struct MyComponent {
+ private countDownFrom: number = 0;
+ private color: Color = Color.Blue;
+
+ build() {
+ }
+}
+
+@Entry
+@Component
+struct ParentComponent {
+ private someColor: Color = Color.Pink;
+
+ build() {
+ Column() {
+ // 创建MyComponent实例,并将创建MyComponent成员变量countDownFrom初始化为10,将成员变量color初始化为this.someColor
+ MyComponent({ countDownFrom: 10, color: this.someColor })
+ }
+ }
+}
+```
+
+
+## build()函数
+
+所有声明在build()函数的语言,我们统称为UI描述语言,UI描述语言需要遵循以下规则:
+
+- \@Entry装饰的自定义组件,其build()函数下的根节点唯一且必要,且必须为容器组件,其中ForEach禁止作为根节点。
+ \@Component装饰的自定义组件,其build()函数下的根节点唯一且必要,可以为非容器组件,其中ForEach禁止作为根节点。
+
+ ```ts
+ @Entry
+ @Component
+ struct MyComponent {
+ build() {
+ // 根节点唯一且必要,必须为容器组件
+ Row() {
+ ChildComponent()
+ }
+ }
+ }
+
+ @Component
+ struct ChildComponent {
+ build() {
+ // 根节点唯一且必要,可为非容器组件
+ Image('test.jpg')
+ }
+ }
+ ```
+
+- 不允许声明本地变量,反例如下。
+
+ ```ts
+ build() {
+ // 反例:不允许声明本地变量
+ let a: number = 1;
+ }
+ ```
+
+- 不允许在UI描述里直接使用console.info,但允许在方法或者函数里使用,反例如下。
+
+ ```ts
+ build() {
+ // 反例:不允许console.info
+ console.info('print debug log');
+ }
+ ```
+
+- 不允许创建本地的作用域,反例如下。
+
+ ```ts
+ build() {
+ // 反例:不允许本地作用域
+ {
+ ...
+ }
+ }
+ ```
+
+- 不允许调用除了被\@Builder装饰以外的方法,允许系统组件的参数是TS方法的返回值。
+
+ ```ts
+ @Component
+ struct ParentComponent {
+ doSomeCalculations() {
+ }
+
+ calcTextValue(): string {
+ return 'Hello World';
+ }
+
+ @Builder doSomeRender() {
+ Text(`Hello World`)
+ }
+
+ build() {
+ Column() {
+ // 反例:不能调用没有用@Builder装饰的方法
+ this.doSomeCalculations();
+ // 正例:可以调用
+ this.doSomeRender();
+ // 正例:参数可以为调用TS方法的返回值
+ Text(this.calcTextValue())
+ }
+ }
+ }
+ ```
+
+- 不允许switch语法,如果需要使用条件判断,请使用if。反例如下。
+
+ ```ts
+ build() {
+ Column() {
+ // 反例:不允许使用switch语法
+ switch (expression) {
+ case 1:
+ Text('...')
+ break;
+ case 2:
+ Image('...')
+ break;
+ default:
+ Text('...')
+ break;
+ }
+ }
+ }
+ ```
+
+- 不允许使用表达式,反例如下。
+
+ ```ts
+ build() {
+ Column() {
+ // 反例:不允许使用表达式
+ (this.aVar > 10) ? Text('...') : Image('...')
+ }
+ }
+ ```
+
+
+## 自定义组件通用样式
+
+自定义组件通过“.”链式调用的形式设置通用样式。
+
+
+```ts
+@Component
+struct MyComponent2 {
+ build() {
+ Button(`Hello World`)
+ }
+}
+
+@Entry
+@Component
+struct MyComponent {
+ build() {
+ Row() {
+ MyComponent2()
+ .width(200)
+ .height(300)
+ .backgroundColor(Color.Red)
+ }
+ }
+}
+```
+
+> **说明:**
+>
+> ArkUI给自定义组件设置样式时,相当于给MyComponent2套了一个不可见的容器组件,而这些样式是设置在容器组件上的,而非直接设置给MyComponent2的Button组件。通过渲染结果我们可以很清楚的看到,背景颜色红色并没有直接生效在Button上,而是生效在Button所处的开发者不可见的容器组件上。
+
+
+## 自定义属性方法
+
+自定义组件不支持提供自定义属性方法,可以借助类似Controller控制器能力,提供自定义接口。
+
+
+```ts
+// 自定义controller
+export class MyComponentController {
+ item: MyComponent = null;
+
+ setItem(item: MyComponent) {
+ this.item = item;
+ }
+
+ changeText(value: string) {
+ this.item.value = value;
+ }
+}
+
+// 自定义组件
+@Component
+export default struct MyComponent {
+ public controller: MyComponentController = null;
+ @State value: string = 'Hello World';
+
+ build() {
+ Column() {
+ Text(this.value)
+ .fontSize(50)
+ }
+ }
+
+ aboutToAppear() {
+ if (this.controller)
+ this.controller.setItem(this); // 绑定controller
+ }
+}
+
+// 使用处逻辑
+@Entry
+@Component
+struct StyleExample {
+ controller = new MyComponentController();
+
+ build() {
+ Column() {
+ MyComponent({ controller: this.controller })
+ }
+ .onClick(() => {
+ this.controller.changeText('Text');
+ })
+ }
+}
+```
+
+在上面的示例中:
+
+1. 通过子组件MyComponent的aboutToAppear方法,把当前的this指针传递给MyComponentController的item成员变量。
+
+2. 在StyleExample父组件中持有controller实例,调用controller的changeText方法,即相当于通过controller持有的MyComponent子组件的this指针,改变MyComponent的状态变量value的值。
+
+通过controller的封装,MyComponent对外暴露了changeText的接口,所有持有controller的实例都可以通过调用changeText接口,改变MyComponent的状态变量value的值。
diff --git a/zh-cn/application-dev/quick-start/arkts-declarative-ui-description.md b/zh-cn/application-dev/quick-start/arkts-declarative-ui-description.md
new file mode 100644
index 0000000000000000000000000000000000000000..d4ca2ea18be32aa8b24892593b097b53a21d65c3
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-declarative-ui-description.md
@@ -0,0 +1,172 @@
+# 声明式UI描述
+
+
+ArkTS以声明方式组合和扩展组件来描述应用程序的UI,同时还提供了基本的属性、事件和子组件配置方法,帮助开发者实现应用交互逻辑。
+
+
+## 创建组件
+
+根据组件构造方法的不同,创建组件包含有参数和无参数两种方式。
+
+> **说明:**
+>
+> 创建组件时不需要new运算符。
+
+
+### 无参数
+
+如果组件的接口定义没有包含必选构造参数,则组件后面的“()”不需要配置任何内容。例如,Divider组件不包含构造参数:
+
+
+```ts
+Column() {
+ Text('item 1')
+ Divider()
+ Text('item 2')
+}
+```
+
+
+### 有参数
+
+如果组件的接口定义包含构造参数,则在组件后面的“()”配置相应参数。
+
+- Image组件的必选参数src。
+
+ ```ts
+ Image('https://xyz/test.jpg')
+ ```
+
+
+- Text组件的非必选参数content。
+
+- ```ts
+ // string类型的参数
+ Text('test')
+ // $r形式引入应用资源,可应用于多语言场景
+ Text($r('app.string.title_value'))
+ // 无参数形式
+ Text()
+ ```
+
+
+- 变量或表达式也可以用于参数赋值,其中表达式返回的结果类型必须满足参数类型要求。
+ 例如,设置变量或表达式来构造Image和Text组件的参数。
+
+ ```ts
+ Image(this.imagePath)
+ Image('https://' + this.imageUrl)
+ Text(`count: ${this.count}`)
+ ```
+
+
+## 配置属性
+
+属性方法以“.”链式调用的方式配置系统组件的样式和其他属性,建议每个属性方法单独写一行。
+
+
+- 配置Text组件的字体大小。
+
+ ```ts
+ Text('test')
+ .fontSize(12)
+ ```
+
+- 配置组件的多个属性。
+
+ ```ts
+ Image('test.jpg')
+ .alt('error.jpg')
+ .width(100)
+ .height(100)
+ ```
+
+- 除了直接传递常量参数外,还可以传递变量或表达式。
+
+ ```ts
+ Text('hello')
+ .fontSize(this.size)
+ Image('test.jpg')
+ .width(this.count % 2 === 0 ? 100 : 200)
+ .height(this.offset + 100)
+ ```
+
+- 对于系统组件,ArkUI还为其属性预定义了一些枚举类型供开发者调用,枚举类型可以作为参数传递,但必须满足参数类型要求。
+ 例如,可以按以下方式配置Text组件的颜色和字体样式。
+
+ ```ts
+ Text('hello')
+ .fontSize(20)
+ .fontColor(Color.Red)
+ .fontWeight(FontWeight.Bold)
+ ```
+
+
+## 配置事件
+
+事件方法以“.”链式调用的方式配置系统组件支持的事件,建议每个属性方法单独写一行。
+
+
+- 使用lambda表达式配置组件的事件方法。
+
+ ```ts
+ Button('Click me')
+ .onClick(() => {
+ this.myText = 'ArkUI';
+ })
+ ```
+
+- 使用匿名函数表达式配置组件的事件方法,要求使用bind,以确保函数体中的this指向当前组件。
+
+ ```ts
+ Button('add counter')
+ .onClick(function(){
+ this.counter += 2;
+ }.bind(this))
+ ```
+
+- 使用组件的成员函数配置组件的事件方法。
+
+ ```ts
+ myClickHandler(): void {
+ this.counter += 2;
+ }
+ ...
+ Button('add counter')
+ .onClick(this.myClickHandler.bind(this))
+ ```
+
+
+## 配置子组件
+
+如果组件支持子组件配置,则需在尾随闭包"{...}"中为组件添加子组件的UI描述。Column、Row、Stack、Grid、List等组件都是容器组件。
+
+
+- 以下是简单的Column组件配置子组件的示例。
+
+ ```ts
+ Column() {
+ Text('Hello')
+ .fontSize(100)
+ Divider()
+ Text(this.myText)
+ .fontSize(100)
+ .fontColor(Color.Red)
+ }
+ ```
+
+- 容器组件均支持子组件配置,可以实现相对复杂的多级嵌套。
+
+ ```ts
+ Column() {
+ Row() {
+ Image('test1.jpg')
+ .width(100)
+ .height(100)
+ Button('click +1')
+ .onClick(() => {
+ console.info('+1 clicked!');
+ })
+ }
+ }
+ ```
diff --git a/zh-cn/application-dev/quick-start/arkts-dynamic-ui-elememt-building.md b/zh-cn/application-dev/quick-start/arkts-dynamic-ui-elememt-building.md
deleted file mode 100644
index 3de63bc1291d343afe73d9117f0ec0157348c657..0000000000000000000000000000000000000000
--- a/zh-cn/application-dev/quick-start/arkts-dynamic-ui-elememt-building.md
+++ /dev/null
@@ -1,385 +0,0 @@
-# 动态构建UI元素
-
-[基本UI描述](arkts-basic-ui-description.md)介绍的是如何创建一个内部UI结构固定的自定义组件,为了满足开发者自定义组件内部UI结构的需求,ArkTS同时提供了动态构建UI元素的能力。
-
-## @Builder
-
-可通过@Builder装饰器进行描述,该装饰器可以修饰一个函数,此函数可以在build函数之外声明,并在build函数中或其他@Builder修饰的函数中使用,从而实现在一个自定义组件内快速生成多个布局内容。使用方式如下面示例所示。
-
-```ts
-// xxx.ets
-@Component
-struct CompB {
- @State CompValue: string = ''
-
- aboutToAppear() {
- console.info('CompB aboutToAppear.')
- }
-
- aboutToDisappear() {
- console.info('CompB aboutToDisappear.')
- }
-
- build() {
- Column() {
- Button(this.CompValue)
- .margin(5)
- }
- }
-}
-
-@Entry
-@Component
-struct CompA {
- size1: number = 100
- @State CompValue1: string = "Hello,CompValue1"
- @State CompValue2: string = "Hello,CompValue2"
- @State CompValue3: string = "Hello,CompValue3"
-
- // @Builder装饰的函数CompC内使用自定义组件CompB
- @Builder CompC(value: string) {
- CompB({ CompValue: value })
- }
-
- @Builder SquareText(label: string) {
- Text(label)
- .fontSize(18)
- .width(1 * this.size1)
- .height(1 * this.size1)
- }
-
- // @Builder装饰的函数RowOfSquareTexts内使用@Builder装饰的函数SquareText
- @Builder RowOfSquareTexts(label1: string, label2: string) {
- Row() {
- this.SquareText(label1)
- this.SquareText(label2)
- }
- .width(2 * this.size1)
- .height(1 * this.size1)
- }
-
- build() {
- Column() {
- Row() {
- this.SquareText("A")
- this.SquareText("B")
- }
- .width(2 * this.size1)
- .height(1 * this.size1)
-
- this.RowOfSquareTexts("C", "D")
- Column() {
- // 使用三次@Builder装饰的自定义组件
- this.CompC(this.CompValue1)
- this.CompC(this.CompValue2)
- this.CompC(this.CompValue3)
- }
- .width(2 * this.size1)
- .height(2 * this.size1)
- }
- .width(2 * this.size1)
- .height(2 * this.size1)
- }
-}
-```
-
-
-## @BuilderParam8+
-
-@BuilderParam装饰器用于修饰自定义组件内函数类型的属性(例如:`@BuilderParam noParam: () => void`),并且在初始化自定义组件时被@BuilderParam修饰的属性必须赋值。
-
-### 引入动机
-
-当开发者创建自定义组件,并想对该组件添加特定功能时(例如在自定义组件中添加一个点击跳转操作)。若直接在组件内嵌入事件方法,将会导致所有引入该自定义组件的地方均增加了该功能。为解决此问题,引入了@BuilderParam装饰器,此装饰器修饰的属性值可为@Builder装饰的函数,开发者可在初始化自定义组件时对此属性进行赋值,为自定义组件增加特定的功能。
-
-### 参数初始化组件
-
-通过参数初始化组件时,将@Builder装饰的函数赋值给@BuilderParam修饰的属性,并在自定义组件内调用该属性值。若@BuilderParam修饰的属性在进行赋值时不带参数(如:`noParam: this.specificNoParam`),则此属性的类型需定义为无返回值的函数(如:`@BuilderParam noParam: () => void`);若带参数(如:`withParam: this.SpecificWithParam('WithParamA')`),则此属性的类型需定义成any(如:`@BuilderParam withParam: any`)。
-
-```ts
-// xxx.ets
-@Component
-struct CustomContainer {
- header: string = ''
- @BuilderParam noParam: () => void
- @BuilderParam withParam: any
- footer: string = ''
-
- build() {
- Column() {
- Text(this.header)
- .fontSize(30)
- this.noParam()
- this.withParam()
- Text(this.footer)
- .fontSize(30)
- }
- }
-}
-
-@Entry
-@Component
-struct CustomContainerUser {
- @Builder specificNoParam() {
- Column() {
- Text('noParam').fontSize(30)
- }
- }
-
- @Builder SpecificWithParam(label: string) {
- Column() {
- Text(label).fontSize(30)
- }
- }
-
- build() {
- Column() {
- CustomContainer({
- header: 'HeaderA',
- noParam: this.specificNoParam,
- withParam: this.SpecificWithParam('WithParamA'),
- footer: 'FooterA'
- })
- Divider()
- .strokeWidth(3)
- .margin(10)
- CustomContainer({
- header: 'HeaderB',
- noParam: this.specificNoParam,
- withParam: this.SpecificWithParam('WithParamB'),
- footer: 'FooterB'
- })
- }
- }
-}
-```
-
-
-
-### 尾随闭包初始化组件
-
-在自定义组件中使用@BuilderParam修饰的属性时也可通过尾随闭包进行初始化(在初始化自定义组件时,组件后紧跟一个大括号“{}”形成尾随闭包场景(`CustomContainer(){}`)。开发者可把尾随闭包看做一个容器,向其中填充内容,如在闭包内增加组件(`{Column(){...}`),闭包内语法规范与build函数一致。此场景下自定义组件内有且仅有一个使用@BuilderParam修饰的属性。
-
-示例:在闭包内添加Column组件并设置点击事件,在Column组件内调用@Builder修饰的specificParam函数,点击Column组件后将自定义组件CustomContainer中header的属性值由“header”改变为“changeHeader”。在初始化自定义组件CustomContainer时,尾随闭包的内容会被赋值给@BuilderParam修饰的closer属性。
-
-```ts
-// xxx.ets
-@Component
-struct CustomContainer {
- header: string = ''
- @BuilderParam closer: () => void
-
- build() {
- Column() {
- Text(this.header)
- .fontSize(30)
- this.closer()
- }
- }
-}
-
-@Builder function specificParam(label1: string, label2: string) {
- Column() {
- Text(label1)
- .fontSize(30)
- Text(label2)
- .fontSize(30)
- }
-}
-
-@Entry
-@Component
-struct CustomContainerUser {
- @State text: string = 'header'
-
- build() {
- Column() {
- CustomContainer({
- header: this.text,
- }) {
- Column() {
- specificParam('testA', 'testB')
- }.backgroundColor(Color.Yellow)
- .onClick(() => {
- this.text = 'changeHeader'
- })
- }
- }
- }
-}
-```
-
-
-
-## @Styles
-
-ArkTS为了避免开发者对重复样式的设置,通过@Styles装饰器可以将多个样式设置提炼成一个方法,直接在组件声明时调用,通过@Styles装饰器可以快速定义并复用自定义样式。当前@Styles仅支持通用属性。
-
-@Styles可以定义在组件内或组件外,在组件外定义时需在方法名前面添加function关键字,组件内定义时则不需要添加function关键字。
-
-```ts
-// xxx.ets
-@Styles function globalFancy () {
- .width(150)
- .height(100)
- .backgroundColor(Color.Pink)
-}
-
-@Entry
-@Component
-struct FancyUse {
- @Styles componentFancy() {
- .width(100)
- .height(200)
- .backgroundColor(Color.Yellow)
- }
-
- build() {
- Column({ space: 10 }) {
- Text('FancyA')
- .globalFancy()
- .fontSize(30)
- Text('FancyB')
- .globalFancy()
- .fontSize(20)
- Text('FancyC')
- .componentFancy()
- .fontSize(30)
- Text('FancyD')
- .componentFancy()
- .fontSize(20)
- }
- }
-}
-```
-
-
-
-@Styles还可以在[StateStyles](../reference/arkui-ts/ts-universal-attributes-polymorphic-style.md)属性内部使用,在组件处于不同的状态时赋予相应的属性。
-
-在StateStyles内可以直接调用组件外定义的@Styles方法,但需要通过this关键字调用组件内定义的@Styles方法。
-
-```ts
-// xxx.ets
-@Styles function globalFancy () {
- .width(120)
- .height(120)
- .backgroundColor(Color.Green)
-}
-
-@Entry
-@Component
-struct FancyUse {
- @Styles componentFancy() {
- .width(80)
- .height(80)
- .backgroundColor(Color.Red)
- }
-
- build() {
- Row({ space: 10 }) {
- Button('Fancy')
- .stateStyles({
- normal: {
- .width(100)
- .height(100)
- .backgroundColor(Color.Blue)
- },
- disabled: this.componentFancy,
- pressed: globalFancy
- })
- }
- }
-}
-```
-
-
-
-## @Extend
-
-@Extend装饰器将新的属性方法添加到Text、Column、Button等内置组件上,通过@Extend装饰器可以快速地扩展原生组件。@Extend不能定义在自定义组件struct内。
-
-```ts
-// xxx.ets
-@Extend(Text) function fancy (fontSize: number) {
- .fontColor(Color.Red)
- .fontSize(fontSize)
- .fontStyle(FontStyle.Italic)
- .fontWeight(600)
-}
-
-@Entry
-@Component
-struct FancyUse {
- build() {
- Row({ space: 10 }) {
- Text("Fancy")
- .fancy(16)
- Text("Fancy")
- .fancy(24)
- Text("Fancy")
- .fancy(32)
- }
- }
-}
-
-```
-
-> **说明:**
->
-> - @Extend装饰器不能定义在自定义组件struct内。
-> - @Extend装饰器内仅支持属性方法设置。
-
-
-
-## @CustomDialog
-
-@CustomDialog装饰器用于装饰自定义弹窗组件,使得弹窗可以动态设置内容及样式。
-
-```ts
-// xxx.ets
-@CustomDialog
-struct DialogExample {
- controller: CustomDialogController
- action: () => void
-
- build() {
- Row() {
- Button('Close CustomDialog')
- .onClick(() => {
- this.controller.close()
- this.action()
- })
- }.padding(20)
- }
-}
-
-@Entry
-@Component
-struct CustomDialogUser {
- dialogController: CustomDialogController = new CustomDialogController({
- builder: DialogExample({ action: this.onAccept }),
- cancel: this.existApp,
- autoCancel: true
- });
-
- onAccept() {
- console.info('onAccept');
- }
-
- existApp() {
- console.info('Cancel dialog!');
- }
-
- build() {
- Column() {
- Button('Click to open Dialog')
- .onClick(() => {
- this.dialogController.open()
- })
- }
- }
-}
-```
-
-
\ No newline at end of file
diff --git a/zh-cn/application-dev/quick-start/arkts-environment.md b/zh-cn/application-dev/quick-start/arkts-environment.md
new file mode 100644
index 0000000000000000000000000000000000000000..240e4358842abcd0beb42e21fc819af60032abcb
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-environment.md
@@ -0,0 +1,71 @@
+# Environment:设备环境查询
+
+
+开发者如果需要应用程序运行的设备的环境参数,以此来作出不同的场景判断,比如多语言,暗黑模式等,需要用到Environment设备环境查询。
+
+
+Environment是ArkUI框架在应用程序启动时创建的单例对象。它为AppStorage提供了一系列描述应用程序运行状态的属性。Environment的所有属性都是不可变的(即应用不可写入),所有的属性都是简单类型。
+
+
+## 使用场景
+
+
+### 从UI中访问Environment参数
+
+- 使用Environment.EnvProp将设备运行的环境变量存入AppStorage中:
+
+ ```ts
+ // 将设备的语言code存入AppStorage,默认值为en
+ // 后续设备的预览设置切换,都将同步到AppStorage中
+ Environment.EnvProp('languageCode', 'en');
+ ```
+
+- 可以使用\@StorageProp链接到Component中。Component会根据设备运行环境的变化而更新:
+
+ ```ts
+ @StorageProp('languageCode') lang : string = 'en';
+ ```
+
+设备环境到Component的更新链:Environment --> AppStorage -->Component。
+
+> **说明:**
+> \@StorageProp关联的环境参数可以在本地更改,但不能同步回AppStorage中,因为应用对环境变量参数是不可写的,只能在Environment中查询。
+
+
+```ts
+// 将设备languageCode存入AppStorage中
+Environment.EnvProp('languageCode', 'en');
+let enable = AppStorage.Get('languageCode');
+
+@Entry
+@Component
+struct Index {
+ @StorageProp('languageCode') languageCode: string = 'en';
+
+ build() {
+ Row() {
+ Column() {
+ // 输出当前设备的languageCode
+ Text(this.languageCode)
+ }
+ }
+ }
+}
+```
+
+
+### 应用逻辑使用Environment
+
+
+```ts
+// 使用Environment.EnvProp将设备运行languageCode存入AppStorage中;
+Environment.EnvProp('languageCode', 'en');
+// 从AppStorage获取单向绑定的languageCode的变量
+const lang: SubscribedAbstractProperty = AppStorage.Prop('languageCode');
+
+if (lang.get() === 'zh') {
+ console.info('你好');
+} else {
+ console.info('Hello!');
+}
+```
diff --git a/zh-cn/application-dev/quick-start/arkts-extend.md b/zh-cn/application-dev/quick-start/arkts-extend.md
new file mode 100644
index 0000000000000000000000000000000000000000..450ec1b2450138023f7abf4b55ee0a857bbf72ed
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-extend.md
@@ -0,0 +1,176 @@
+# \@Extend:定义扩展组件样式
+
+
+在前文的示例中,可以使用\@Styles用于样式的扩展,在\@Styles的基础上,我们提供了\@Extend,用于扩展原生组件样式。
+
+
+> **说明:**
+> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+
+## 装饰器使用说明
+
+
+### 语法
+
+
+```ts
+@Extend(UIComponentName) function functionName { ... }
+```
+
+
+### 使用规则
+
+- 和\@Styles不同,\@Extend仅支持定义在全局,不支持在组件内部定义。
+
+- 和\@Styles不同,\@Extend支持封装指定的组件的私有属性和私有事件和预定义相同组件的\@Extend的方法。
+
+ ```ts
+ // @Extend(Text)可以支持Text的私有属性fontColor
+ @Extend(Text) function fancy () {
+ .fontColor(Color.Red)
+ }
+ // superFancyText可以调用预定义的fancy
+ @Extend(Text) function superFancyText(size:number) {
+ .fontSize(size)
+ .fancy()
+ }
+ ```
+
+
+- 和\@Styles不同,\@Extend装饰的方法支持参数,开发者可以在调用时传递参数,调用遵循TS方法传值调用。
+
+ ```ts
+ // xxx.ets
+ @Extend(Text) function fancy (fontSize: number) {
+ .fontColor(Color.Red)
+ .fontSize(fontSize)
+ }
+
+ @Entry
+ @Component
+ struct FancyUse {
+ build() {
+ Row({ space: 10 }) {
+ Text('Fancy')
+ .fancy(16)
+ Text('Fancy')
+ .fancy(24)
+ }
+ }
+ }
+ ```
+
+- \@Extend装饰的方法的参数可以为function,作为Event事件的句柄。
+
+ ```ts
+ @Extend(Text) function makeMeClick(onClick: () => void) {
+ .backgroundColor(Color.Blue)
+ .onClick(onClick)
+ }
+
+ @Entry
+ @Component
+ struct FancyUse {
+ @State label: string = 'Hello World';
+
+ onClickHandler() {
+ this.label = 'Hello ArkUI';
+ }
+
+ build() {
+ Row({ space: 10 }) {
+ Text(`${this.label}`)
+ .makeMeClick(this.onClickHandler.bind(this))
+ }
+ }
+ }
+ ```
+
+- \@Extend的参数可以为[状态变量](arkts-state-management-overview.md),当状态变量改变时,UI可以正常的被刷新渲染。
+
+ ```ts
+ @Extend(Text) function fancy (fontSize: number) {
+ .fontColor(Color.Red)
+ .fontSize(fontSize)
+ }
+
+ @Entry
+ @Component
+ struct FancyUse {
+ @State fontSizeValue: number = 20
+ build() {
+ Row({ space: 10 }) {
+ Text('Fancy')
+ .fancy(this.fontSizeValue)
+ .onClick(() => {
+ this.fontSizeValue = 30
+ })
+ }
+ }
+ }
+ ```
+
+
+## 使用场景
+
+以下示例声明了3个Text组件,每个Text组件均设置了fontStyle、fontWeight和backgroundColor样式。
+
+
+```ts
+@Entry
+@Component
+struct FancyUse {
+ @State label: string = 'Hello World'
+
+ build() {
+ Row({ space: 10 }) {
+ Text(`${this.label}`)
+ .fontStyle(FontStyle.Italic)
+ .fontWeight(100)
+ .backgroundColor(Color.Blue)
+ Text(`${this.label}`)
+ .fontStyle(FontStyle.Italic)
+ .fontWeight(200)
+ .backgroundColor(Color.Pink)
+ Text(`${this.label}`)
+ .fontStyle(FontStyle.Italic)
+ .fontWeight(300)
+ .backgroundColor(Color.Orange)
+ }.margin('20%')
+ }
+}
+```
+
+\@Extend将样式组合复用,示例如下。
+
+
+```ts
+@Extend(Text) function fancyText(weightValue: number, color: Color) {
+ .fontStyle(FontStyle.Italic)
+ .fontWeight(weightValue)
+ .backgroundColor(color)
+}
+```
+
+通过\@Extend组合样式后,使得代码更加简洁,增强可读性。
+
+
+```ts
+@Entry
+@Component
+struct FancyUse {
+ @State label: string = 'Hello World'
+
+ build() {
+ Row({ space: 10 }) {
+ Text(`${this.label}`)
+ .fancyText(100, Color.Blue)
+ Text(`${this.label}`)
+ .fancyText(200, Color.Pink)
+ Text(`${this.label}`)
+ .fancyText(200, Color.Orange)
+ }.margin('20%')
+ }
+}
+```
diff --git a/zh-cn/application-dev/quick-start/arkts-get-started.md b/zh-cn/application-dev/quick-start/arkts-get-started.md
index af97f571b9c0fa336d501b3cd322f65e61fb2cd4..378d07d84d7608023257b25cdb4dab983b9cc674 100644
--- a/zh-cn/application-dev/quick-start/arkts-get-started.md
+++ b/zh-cn/application-dev/quick-start/arkts-get-started.md
@@ -1,30 +1,17 @@
# 初识ArkTS语言
-ArkTS是OpenHarmony优选的主力应用开发语言。ArkTS基于TypeScript(简称TS)语言扩展而来,是TS的超集。
-- ArkTS继承了TS的所有特性。
+ArkTS是OpenHarmony优选的主力应用开发语言。ArkTS围绕应用开发在[TypeScript](https://www.typescriptlang.org/)(简称TS)生态基础上做了进一步扩展,继承了TS的所有特性,是TS的超集。因此,在学习ArkTS语言之前,建议开发者具备TS语言开发能力。
-- 当前,ArkTS在TS的基础上主要扩展了[声明式UI](arkts-basic-ui-description.md)能力,让开发者能够以更简洁、更自然的方式开发高性能应用。
- 当前扩展的声明式UI能力包括如下特性。
+当前,ArkTS在TS的基础上主要扩展了如下能力:
- - [基本UI描述](arkts-basic-ui-description.md):ArkTS定义了各种装饰器、自定义组件、UI描述机制,再配合UI开发框架中的内置组件及其相关的事件方法、属性方法等共同构成了UI开发的主体。
- - [状态管理](arkts-state-mgmt-page-level.md):ArkTS提供了多维度的状态管理机制,在UI开发框架中,和UI相关联的数据,不仅可以在组件内使用,还可以在不同组件层级间传递,比如父子组件之间、爷孙组件之间,也可以是应用全局范围内的传递,还可以是跨设备传递。另外,从数据的传递形式来看,可分为只读的单向传递和可变更的双向传递。开发者可以灵活的利用这些能力来实现数据和UI的联动。
- - [动态构建UI元素](arkts-dynamic-ui-elememt-building.md):ArkTS提供了动态构建UI元素的能力,不仅可以自定义组件内部的UI结构,还可以复用组件样式,扩展原生组件。
- - [渲染控制](arkts-rendering-control.md):ArkTS提供了渲染控制的能力。条件渲染可根据应用的不同状态,渲染对应状态下的UI内容。循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件。
- - [使用限制与扩展](arkts-restrictions-and-extensions.md):ArkTS在使用过程中存在限制与约束,同时也扩展了双向绑定等能力。
-- 未来,ArkTS会结合应用开发/运行的需求持续演进,逐步提供并行和并发能力增强、系统类型增强、分布式开发范式等更多特性。
+- [基本语法](arkts-basic-syntax-overview.md):ArkTS定义了声明式UI描述、自定义组件和动态扩展UI元素的能力,再配合ArkUI开发框架中的系统组件及其相关的事件方法、属性方法等共同构成了UI开发的主体。
-下面我们以一个具体的示例来说明ArkTS的基本组成。如下图所示的代码示例,UI界面包含两段文本、一条分割线和一个按钮,当开发者点击按钮时,文本内容会从'Hello World'变为 'Hello ArkUI'。
+- [状态管理](arkts-state-management-overview.md):ArkTS提供了多维度的状态管理机制。在UI开发框架中,与UI相关联的数据可以在组件内使用,也可以在不同组件层级间传递,比如父子组件之间、爷孙组件之间,还可以在应用全局范围内传递或跨设备传递。另外,从数据的传递形式来看,可分为只读的单向传递和可变更的双向传递。开发者可以灵活的利用这些能力来实现数据和UI的联动。
-
+- [渲染控制](arkts-rendering-control-overview.md):ArkTS提供了渲染控制的能力。条件渲染可根据应用的不同状态,渲染对应状态下的UI内容。循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件。数据懒加载从数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。
-这个示例中所包含的ArkTS声明式开发范式的基本组成说明如下:
-- 装饰器: 用于装饰类、结构、方法以及变量,赋予其特殊的含义,如上述示例中@Entry、@Component和@State都是装饰器。 具体而言,@Component表示这是个自定义组件;@Entry则表示这是个入口组件;@State表示这是组件中的状态变量,这个变量变化会触发UI刷新。
-- 自定义组件:可复用的UI单元,可组合其他组件,如上述被@Component装饰的struct Hello。
-- UI描述:声明式的方法来描述UI的结构,例如build()方法中的代码块。
-- 内置组件:ArkTS中默认内置的基础组件、容器组件、媒体组件、绘制组件、画布组件等各种组件,开发者可以直接调用,如示例中的Column、Text、Divider、Button等。
-- 属性方法:用于组件属性的配置,如fontSize()、width()、height()、color()等,可通过链式调用的方式设置多项属性。
-- 事件方法:用于添加组件对事件的响应逻辑,如跟随在Button后面的onClick(),同样可以通过链式调用的方式设置多个事件响应逻辑。
+未来,ArkTS会结合应用开发/运行的需求持续演进,逐步提供并行和并发能力增强、系统类型增强、分布式开发范式等更多特性。
diff --git a/zh-cn/application-dev/quick-start/arkts-link.md b/zh-cn/application-dev/quick-start/arkts-link.md
new file mode 100644
index 0000000000000000000000000000000000000000..d4094233d4df403d027fd6e4a89b665391ee34c7
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-link.md
@@ -0,0 +1,185 @@
+# \@Link:父子双向同步
+
+
+子组件中被\@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。
+
+
+> **说明:**
+> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+
+## 概述
+
+\@Link装饰的变量与其父组件中的数据源共享相同的值。
+
+
+## 装饰器使用规则说明
+
+| \@Link变量装饰器 | 说明 |
+| ----------- | ---------------------------------------- |
+| 装饰器参数 | 无 |
+| 同步类型 | 双向同步。
父组件中\@State, \@StorageLink和\@Link 和子组件\@Link可以建立双向数据同步,反之亦然。 |
+| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考[观察变化](#观察变化)。
类型必须被指定,且和双向绑定状态变量的类型相同。
不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。
**说明:**
不支持Length、ResourceStr、ResourceColor类型,Length、ResourceStr、ResourceColor为简单类型和复杂类型的联合类型。 |
+| 被装饰变量的初始值 | 无,禁止本地初始化。 |
+
+
+## 变量的传递/访问规则说明
+
+| 传递/访问 | 说明 |
+| ---------- | ---------------------------------------- |
+| 从父组件初始化和更新 | 必选。与父组件\@State, \@StorageLink和\@Link 建立双向绑定。允许父组件中\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp装饰变量初始化子组件\@Link。
从API version 9开始,\@Link子组件从父组件初始化\@State的语法为Comp({ aLink: this.aState })。同样Comp({aLink: $aState})也支持。 |
+| 用于初始化子组件 | 允许,可用于初始化常规变量、\@State、\@Link、\@Prop、\@Provide。 |
+| 是否支持组件外访问 | 私有,只能在所属组件内访问。 |
+
+ **图1** 初始化规则图示
+
+
+
+
+## 观察变化和行为表现
+
+
+### 观察变化
+
+- 当装饰的数据类型为boolean、string、number类型时,可以同步观察到数值的变化,示例请参考[简单类型和类对象类型的@Link](#简单类型和类对象类型的link)。
+
+- 当装饰的数据类型为class或者Object时,可以观察到赋值和属性赋值的变化,即Object.keys(observedObject)返回的所有属性,示例请参考[简单类型和类对象类型的@Link](#简单类型和类对象类型的link)。
+
+- 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化,示例请参考[数组类型的@Link](#数组类型的link)。
+
+
+### 框架行为
+
+\@Link装饰的变量和其所述的自定义组件共享生命周期。
+
+为了了解\@Link变量初始化和更新机制,有必要先了解父组件和和拥有\@Link变量的子组件的关系,初始渲染和双向更新的流程(以父组件为\@State为例)。
+
+1. 初始渲染:执行父组件的build()函数后将创建子组件的新实例。初始化过程如下:
+ 1. 必须指定父组件中的\@State变量,用于初始化子组件的\@Link变量。子组件的\@Link变量值与其父组件的数据源变量保持同步(双向数据同步)。
+ 2. 父组件的\@State状态变量包装类通过构造函数传给子组件,子组件的\@Link包装类拿到父组件的\@State的状态变量后,将当前\@Link包装类this指针注册给父组件的\@State变量。
+
+2. \@Link的数据源的更新:即父组件中状态变量更新,引起相关子组件的\@Link的更新。处理步骤:
+ 1. 通过初始渲染的步骤可知,子组件\@Link包装类把当前this指针注册给父组件。父组件\@State变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(比如\@Link包装类)。
+ 2. 通知\@Link包装类更新后,子组件中所有依赖\@Link状态变量的系统组件(elementId)都会被通知更新。以此实现父组件对子组件的状态数据同步。
+
+3. \@Link的更新:当子组件中\@Link更新后,处理步骤如下(以父组件为\@State为例):
+ 1. \@Link更新后,调用父组件的\@State包装类的set方法,将更新后的数值同步回父组件。
+ 2. 子组件\@Link和父组件\@State分别遍历依赖的系统组件,进行对应的UI的更新。以此实现子组件\@Link同步回父组件\@State。
+
+
+## 使用场景
+
+
+### 简单类型和类对象类型的\@Link
+
+以下示例中,点击父组件ShufflingContainer中的“Parent View: Set yellowButton”和“Parent View: Set GreenButton”,可以从父组件将变化同步给子组件,子组件GreenButton和YellowButton中\@Link装饰变量的变化也会同步给其父组件。
+
+
+```ts
+class GreenButtonState {
+ width: number = 0;
+ constructor(width: number) {
+ this.width = width;
+ }
+}
+@Component
+struct GreenButton {
+ @Link greenButtonState: GreenButtonState;
+ build() {
+ Button('Green Button')
+ .width(this.greenButtonState.width)
+ .height(150.0)
+ .backgroundColor('#00ff00')
+ .onClick(() => {
+ if (this.greenButtonState.width < 700) {
+ // 更新class的属性,变化可以被观察到同步回父组件
+ this.greenButtonState.width += 125;
+ } else {
+ // 更新class,变化可以被观察到同步回父组件
+ this.greenButtonState = new GreenButtonState(100);
+ }
+ })
+ }
+}
+@Component
+struct YellowButton {
+ @Link yellowButtonState: number;
+ build() {
+ Button('Yellow Button')
+ .width(this.yellowButtonState)
+ .height(150.0)
+ .backgroundColor('#ffff00')
+ .onClick(() => {
+ // 子组件的简单类型可以同步回父组件
+ this.yellowButtonState += 50.0;
+ })
+ }
+}
+@Entry
+@Component
+struct ShufflingContainer {
+ @State greenButtonState: GreenButtonState = new GreenButtonState(300);
+ @State yellowButtonProp: number = 100;
+ build() {
+ Column() {
+ // 简单类型从父组件@State向子组件@Link数据同步
+ Button('Parent View: Set yellowButton')
+ .onClick(() => {
+ this.yellowButtonProp = (this.yellowButtonProp < 700) ? this.yellowButtonProp + 100 : 100;
+ })
+ // class类型从父组件@State向子组件@Link数据同步
+ Button('Parent View: Set GreenButton')
+ .onClick(() => {
+ this.greenButtonState.width = (this.greenButtonState.width < 700) ? this.greenButtonState.width + 100 : 100;
+ })
+ // class类型初始化@Link
+ GreenButton({ greenButtonState: $greenButtonState })
+ // 简单类型初始化@Link
+ YellowButton({ yellowButtonState: $yellowButtonProp })
+ }
+ }
+}
+```
+
+
+### 数组类型的\@Link
+
+
+```ts
+@Component
+struct Child {
+ @Link items: number[];
+
+ build() {
+ Column() {
+ Button(`Button1: push`).onClick(() => {
+ this.items.push(this.items.length + 1);
+ })
+ Button(`Button2: replace whole item`).onClick(() => {
+ this.items = [100, 200, 300];
+ })
+ }
+ }
+}
+
+@Entry
+@Component
+struct Parent {
+ @State arr: number[] = [1, 2, 3];
+
+ build() {
+ Column() {
+ Child({ items: $arr })
+ ForEach(this.arr,
+ item => {
+ Text(`${item}`)
+ },
+ item => item.toString()
+ )
+ }
+ }
+}
+```
+
+
+上文所述,ArkUI框架可以观察到数组元素的添加,删除和替换。在该示例中\@State和\@Link的类型是相同的number[],不允许将\@Link定义成number类型(\@Link item : number),并在父组件中用\@State数组中每个数据项创建子组件。如果要使用这个场景,可以参考[\@Prop](arkts-prop.md)和\@Observed。
diff --git a/zh-cn/application-dev/quick-start/arkts-localstorage.md b/zh-cn/application-dev/quick-start/arkts-localstorage.md
new file mode 100644
index 0000000000000000000000000000000000000000..b651f0a03e4f83456f742ff1521178c87eb3d781
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-localstorage.md
@@ -0,0 +1,425 @@
+# LocalStorage:页面级UI状态存储
+
+
+LocalStorage是页面级的UI状态存储,通过\@Entry装饰器接受的参数可以在页面内共享同一个LocalStorage实例。LocalStorage也可以在UIAbility内,页面间共享状态。
+
+
+本文仅介绍LocalStorage使用场景和相关的装饰器:\@LocalStorageProp和\@LocalStorageLink。
+
+
+> **说明:**
+>
+> 本模块从API version 9开始支持。
+
+
+## 概述
+
+LocalStorage是ArkTS为构建页面级别状态变量提供存储的内存内“数据库”。
+
+- 应用程序可以创建多个LocalStorage实例,LocalStorage实例可以在页面内共享,也可以通过GetShared接口,获取在UIAbility里创建的GetShared,实现跨页面、UIAbility内共享。
+
+- 组件树的根节点,即被\@Entry装饰的\@Component,可以被分配一个LocalStorage实例,此组件的所有子组件实例将自动获得对该LocalStorage实例的访问权限;
+
+- 被\@Component装饰的组件最多可以访问一个LocalStorage实例和[AppStorage](arkts-appstorage.md),未被\@Entry装饰的组件不可被独立分配LocalStorage实例,只能接受父组件通过\@Entry传递来的LocalStorage实例。一个LocalStorage实例在组件树上可以被分配给多个组件。
+
+- LocalStorage中的所有属性都是可变的。
+
+应用程序决定LocalStorage对象的生命周期。当应用释放最后一个指向LocalStorage的引用时,比如销毁最后一个自定义组件,LocalStorage将被JS Engine垃圾回收。
+
+LocalStorage根据与\@Component装饰的组件的的同步类型不同,提供了两个装饰器:
+
+- [@LocalStorageProp](#localstorageprop):\@LocalStorageProp装饰的变量和与LocalStorage中给定属性建立单行同步关系。
+
+- [@LocalStorageLink](#localstoragelink):\@LocalStorageLink装饰的变量和在\@Component中创建与LocalStorage中给定属性建立双向同步关系。
+
+
+## 限制条件
+
+LocalStorage创建后,命名属性的类型不可更改。后续调用Set时必须使用相同类型的值。
+
+
+## \@LocalStorageProp
+
+在上文中已经提到,如果要建立LocalStorage和自定义组件的联系,需要使用\@LocalStorageProp和\@LocalStorageLink装饰器。使用\@LocalStorageProp(key)/\@LocalStorageLink(key)装饰组件内的变量,key标识了LocalStorage的属性。
+
+
+当自定义组件初始化的时候,\@LocalStorageProp(key)/\@LocalStorageLink(key)装饰的变量会通过给定的key,绑定在LocalStorage对应是属性,完成初始化。本地初始化是必要的,因为无法保证LocalStorage一定存在给定的key(这取决于应用逻辑,是否在组件初始化之前在LocalStorage实例中存入对应的属性)。
+
+
+> **说明:**
+>
+> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+
+\@LocalStorageProp(key)是和LocalStorage中key对应的属性建立单向数据同步,我们允许本地改变的发生,但是对于\@LocalStorageProp,本地的修改永远不会同步回LocalStorage中,相反,如果LocalStorage给定key的属性发生改变,改变会被同步给\@LocalStorageProp,并覆盖掉本地的修改。
+
+
+### 装饰器使用规则说明
+
+| \@LocalStorageProp变量装饰器 | 说明 |
+| ----------------------- | ---------------------------------------- |
+| 装饰器参数 | key:常量字符串,必填(字符串需要有引号)。 |
+| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考[观察变化和行为表现](#观察变化和行为表现)。
类型必须被指定,且必须和LocalStorage中对应属性相同。不支持any,不允许使用undefined和null。 |
+| 同步类型 | 单向同步:从LocalStorage的对应属性到组件的状态变量。组件本地的修改是允许的,但是LocalStorage中给定的属性一旦发生变化,将覆盖本地的修改。 |
+| 被装饰变量的初始值 | 必须指定,如果LocalStorage实例中不存在属性,则作为初始化默认值,并存入LocalStorage中。 |
+
+
+### 变量的传递/访问规则说明
+
+| 传递/访问 | 说明 |
+| ---------- | ---------------------------------------- |
+| 从父节点初始化和更新 | 禁止,\@LocalStorageProp不支持从父节点初始化,只能从LocalStorage中key对应的属性初始化,如果没有对应key的话,将使用本地默认值初始化。 |
+| 初始化子节点 | 支持,可用于初始化\@State、\@Link、\@Prop、\@Provide。 |
+| 是否支持组件外访问 | 否。 |
+
+ **图1** \@LocalStorageProp初始化规则图示
+
+
+
+
+### 观察变化和行为表现
+
+**观察变化**
+
+
+- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
+
+- 当装饰的数据类型为class或者Object时,可以观察到赋值和属性赋值的变化,即Object.keys(observedObject)返回的所有属性。
+
+- 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化。
+
+
+**框架行为**
+
+
+- 当\@LocalStorageProp(key)装饰的数值改变被观察到时,修改不会被同步回LocalStorage对应属性键值key的属性中。
+
+- 当前\@LocalStorageProp(key)单向绑定的数据会被修改,即仅限于当前组件的私有成员变量改变,其他的绑定该key的数据不会同步改变。
+
+- 当\@LocalStorageProp(key)装饰的数据本身是状态变量,它的改变虽然不会同步回LocalStorage中,但是会引起所属的自定义组件的重新渲染。
+
+- 当LocalStorage中key对应的属性发生改变时,会同步给所有\@LocalStorageProp(key)装饰的数据,\@LocalStorageProp(key)本地的修改将被覆盖。
+
+
+## \@LocalStorageLink
+
+如果我们需要将自定义组件的状态变量的更新同步回LocalStorage,就需要用到\@LocalStorageLink。
+
+\@LocalStorageLink(key)是和LocalStorage中key对应的属性建立双向数据同步:
+
+1. 本地修改发生,该修改会被回LocalStorage中;
+
+2. LocalStorage中的修改发生后,该修改会被同步到所有绑定LocalStorage对应key的属性上,包括单向(\@LocalStorageProp和通过prop创建的单向绑定变量)、双向(\@LocalStorageLink和通过link创建的双向绑定变量)变量。
+
+
+### 装饰器使用规则说明
+
+| \@LocalStorageLink变量装饰器 | 说明 |
+| ----------------------- | ---------------------------------------- |
+| 装饰器参数 | key:常量字符串,必填(字符串需要有引号)。 |
+| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考[观察变化和行为表现](#观察变化和行为表现)。
类型必须被指定,且必须和LocalStorage中对应属性相同。不支持any,不允许使用undefined和null。 |
+| 同步类型 | 双向同步:从LocalStorage的对应属性到自定义组件,从自定义组件到LocalStorage对应属性。 |
+| 被装饰变量的初始值 | 必须指定,如果LocalStorage实例中不存在属性,则作为初始化默认值,并存入LocalStorage中。 |
+
+
+### 变量的传递/访问规则说明
+
+| 传递/访问 | 说明 |
+| ---------- | ---------------------------------------- |
+| 从父节点初始化和更新 | 禁止,\@LocalStorageLink不支持从父节点初始化,只能从LocalStorage中key对应的属性初始化,如果没有对应key的话,将使用本地默认值初始化。 |
+| 初始化子节点 | 支持,可用于初始化\@State、\@Link、\@Prop、\@Provide。 |
+| 是否支持组件外访问 | 否。 |
+
+
+ **图2** \@LocalStorageLink初始化规则图示
+
+
+
+
+
+### 观察变化和行为表现
+
+**观察变化**
+
+
+- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
+
+- 当装饰的数据类型为class或者Object时,可以观察到赋值和属性赋值的变化,即Object.keys(observedObject)返回的所有属性。
+
+- 当装饰的对象是array时,可以观察到数组添加、删除、更新数组单元的变化。
+
+
+**框架行为**
+
+
+1. 当\@LocalStorageLink(key)装饰的数值改变被观察到时,修改将被同步回LocalStorage对应属性键值key的属性中。
+
+2. LocalStorage中属性键值key对应的数据一旦改变,属性键值key绑定的所有的数据(包括双向\@LocalStorageLink和单向\@LocalStorageProp)都将同步修改;
+
+3. 当\@LocalStorageLink(key)装饰的数据本身是状态变量,它的改变不仅仅会同步回LocalStorage中,还会引起所属的自定义组件的重新渲染。
+
+
+## 使用场景
+
+
+### 应用逻辑使用LocalStorage
+
+
+```ts
+let storage = new LocalStorage({ 'PropA': 47 }); // 创建新实例并使用给定对象初始化
+let propA = storage.get('PropA') // propA == 47
+let link1 = storage.link('PropA'); // link1.get() == 47
+let link2 = storage.link('PropA'); // link2.get() == 47
+let prop = storage.prop('PropA'); // prop.get() = 47
+link1.set(48); // two-way sync: link1.get() == link2.get() == prop.get() == 48
+prop.set(1); // one-way sync: prop.get()=1; but link1.get() == link2.get() == 48
+link1.set(49); // two-way sync: link1.get() == link2.get() == prop.get() == 49
+```
+
+
+### 从UI内部使用LocalStorage
+
+除了应用程序逻辑使用LocalStorage,还可以借助LocalStorage相关的两个装饰器\@LocalStorageProp和\@LocalStorageLink,在UI组件内部获取到LocalStorage实例中存储的状态变量。
+
+本示例以\@LocalStorage为例,展示了:
+
+- 使用构造函数创建LocalStorage实例storage;
+
+- 使用\@Entry装饰器将storage添加到CompA顶层组件中;
+
+- \@LocalStorageLink绑定LocalStorage对给定的属性,建立双向数据同步。
+
+ ```ts
+ // 创建新实例并使用给定对象初始化
+ let storage = new LocalStorage({ 'PropA': 47 });
+
+ @Component
+ struct Child {
+ // @LocalStorageLink变量装饰器与LocalStorage中的'ProA'属性建立双向绑定
+ @LocalStorageLink('PropA') storLink2: number = 1;
+
+ build() {
+ Button(`Child from LocalStorage ${this.storLink2}`)
+ // 更改将同步至LocalStorage中的'ProA'以及Parent.storLink1
+ .onClick(() => this.storLink2 += 1)
+ }
+ }
+ // 使LocalStorage可从@Component组件访问
+ @Entry(storage)
+ @Component
+ struct CompA {
+ // @LocalStorageLink变量装饰器与LocalStorage中的'ProA'属性建立双向绑定
+ @LocalStorageLink('PropA') storLink1: number = 1;
+
+ build() {
+ Column({ space: 15 }) {
+ Button(`Parent from LocalStorage ${this.storLink1}`) // initial value from LocalStorage will be 47, because 'PropA' initialized already
+ .onClick(() => this.storLink1 += 1)
+ // @Component子组件自动获得对CompA LocalStorage实例的访问权限。
+ Child()
+ }
+ }
+ }
+ ```
+
+
+### \@LocalStorageProp和LocalStorage单向同步的简单场景
+
+在下面的示例中,CompA 组件和Child组件分别在本地创建了与storage的'PropA'对应属性的单向同步的数据,我们可以看到:
+
+- CompA中对this.storProp1的修改,只会在CompA中生效,并没有同步回storage;
+
+- Child组件中,Text绑定的storProp2 依旧显示47。
+
+ ```ts
+ // 创建新实例并使用给定对象初始化
+ let storage = new LocalStorage({ 'PropA': 47 });
+ // 使LocalStorage可从@Component组件访问
+ @Entry(storage)
+ @Component
+ struct CompA {
+ // @LocalStorageProp变量装饰器与LocalStorage中的'ProA'属性建立单向绑定
+ @LocalStorageProp('PropA') storProp1: number = 1;
+
+ build() {
+ Column({ space: 15 }) {
+ // 点击后从47开始加1,只改变当前组件显示的storProp1,不会同步到LocalStorage中
+ Button(`Parent from LocalStorage ${this.storProp1}`)
+ .onClick(() => this.storProp1 += 1)
+ Child()
+ }
+ }
+ }
+
+ @Component
+ struct Child {
+ // @LocalStorageProp变量装饰器与LocalStorage中的'ProA'属性建立单向绑定
+ @LocalStorageProp('PropA') storProp2: number = 2;
+
+ build() {
+ Column({ space: 15 }) {
+ // 当CompA改变时,当前storProp2不会改变,显示47
+ Text(`Parent from LocalStorage ${this.storProp2}`)
+ }
+ }
+ }
+ ```
+
+
+### \@LocalStorageLink和LocalStorage双向同步的简单场景
+
+下面的示例展示了\@LocalStorageLink装饰的数据和LocalStorage双向同步的场景
+
+
+```ts
+// 构造LocalStorage实例
+let storage = new LocalStorage({ 'PropA': 47 });
+// 调用link9+接口构造'PropA'的双向同步数据,linkToPropA 是全部变量
+let linkToPropA = storage.link('PropA');
+
+@Entry(storage)
+@Component
+struct CompA {
+
+ // @LocalStorageLink('PropA')在CompA自定义组件中创建'PropA'的双向同步数据,初始值为47,因为在构造LocalStorage已经给“PropA”设置47
+ @LocalStorageLink('PropA') storLink: number = 1;
+
+ build() {
+ Column() {
+ Text(`incr @LocalStorageLink variable`)
+ // 点击“incr @LocalStorageLink variable”,this.storLink加1,改变同步回storage,全局变量linkToPropA也会同步改变
+
+ .onClick(() => this.storLink += 1)
+
+ // 并不建议在组件内使用全局变量linkToPropA.get(),因为可能会有生命周期不同引起的错误。
+ Text(`@LocalStorageLink: ${this.storLink} - linkToPropA: ${linkToPropA.get()}`)
+ }
+ }
+}
+```
+
+
+### 兄弟节点之间同步状态变量
+
+下面的示例展示了通过\@LocalStorageLink双向同步兄弟节点之间的状态。
+
+先看Parent自定义组件中发生的变化:
+
+1. 点击“countStorage ${this.playCount} incr by 1”,this.playCount减1,修改同步回LocalStorage中,Child组件中的playCountLink绑定的组件会同步刷新;
+
+2. 点击“countStorage ${this.playCount} incr by 1”,调用LocalStorage的set接口,更新LocalStorage中“countStorage”对应的属性,Child组件中的playCountLink绑定的组件会同步刷新;
+
+3. Text组件“playCount in LocalStorage for debug ${storage.get<number>('countStorage')}”没有同步刷新,原因是因为storage.get<number>('countStorage')返回的是常规变量,常规变量的更新并不会引起Text组件的重新渲染。
+
+Child自定义组件中的变化:
+
+1. playCountLink的刷新会同步回LocalStorage,并且引起兄弟组件和父组件相应的刷新。
+
+ ```ts
+ let storage = new LocalStorage({ countStorage: 1 });
+
+ @Component
+ struct Child {
+ // 子组件实例的名字
+ label: string = 'no name';
+ // 和LocalStorage中“countStorage”的双向绑定数据
+ @LocalStorageLink('countStorage') playCountLink: number = 0;
+
+ build() {
+ Row() {
+ Text(this.label)
+ .width(50).height(60).fontSize(12)
+ Text(`playCountLink ${this.playCountLink}: inc by 1`)
+ .onClick(() => {
+ this.playCountLink += 1;
+ })
+ .width(200).height(60).fontSize(12)
+ }.width(300).height(60)
+ }
+ }
+
+ @Entry(storage)
+ @Component
+ struct Parent {
+ @LocalStorageLink('countStorage') playCount: number = 0;
+
+ build() {
+ Column() {
+ Row() {
+ Text('Parent')
+ .width(50).height(60).fontSize(12)
+ Text(`playCount ${this.playCount} dec by 1`)
+ .onClick(() => {
+ this.playCount -= 1;
+ })
+ .width(250).height(60).fontSize(12)
+ }.width(300).height(60)
+
+ Row() {
+ Text('LocalStorage')
+ .width(50).height(60).fontSize(12)
+ Text(`countStorage ${this.playCount} incr by 1`)
+ .onClick(() => {
+ storage.set('countStorage', 1 + storage.get('countStorage'));
+ })
+ .width(250).height(60).fontSize(12)
+ }.width(300).height(60)
+
+ Child({ label: 'ChildA' })
+ Child({ label: 'ChildB' })
+
+ Text(`playCount in LocalStorage for debug ${storage.get('countStorage')}`)
+ .width(300).height(60).fontSize(12)
+ }
+ }
+ }
+ ```
+
+
+### 将LocalStorage实例从UIAbility共享到一个或多个视图
+
+上面的实例中,LocalStorage的实例仅仅在一个\@Entry装饰的组件和其所属的子组件(一个页面)中共享,如果希望其在多个视图中共享,可以在所属UIAbility中创建LocalStorage实例,并调用windowStage.[loadContent](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-window.md#loadcontent9)。
+
+
+```ts
+// EntryAbility.ts
+import UIAbility from '@ohos.app.ability.UIAbility';
+import window from '@ohos.window';
+
+export default class EntryAbility extends UIAbility {
+ storage: LocalStorage = new LocalStorage({
+ 'PropA': 47
+ });
+
+ onWindowStageCreate(windowStage: window.WindowStage) {
+ windowStage.loadContent('pages/Index', this.storage);
+ }
+}
+```
+
+在UI页面通过GetShared接口获取在通过loadContent共享的LocalStorage实例。
+
+
+```ts
+// 通过GetShared接口获取stage共享的Storage实例
+let storage = LocalStorage.GetShared()
+
+@Entry(storage)
+@Component
+struct CompA {
+ // can access LocalStorage instance using
+ // @LocalStorageLink/Prop decorated variables
+ @LocalStorageLink('PropA') varA: number = 1;
+
+ build() {
+ Column() {
+ Text(`${this.varA}`).fontSize(50)
+ }
+ }
+}
+```
+
+
+> **说明:**
+>
+> 对于开发者更建议使用这个方式来构建LocalStorage的实例,并且在创建LocalStorage实例的时候就写入默认值,因为默认值可以作为运行异常的备份,也可以用作页面的单元测试。
diff --git a/zh-cn/application-dev/quick-start/arkts-observed-and-objectlink.md b/zh-cn/application-dev/quick-start/arkts-observed-and-objectlink.md
new file mode 100644
index 0000000000000000000000000000000000000000..417c45305c862dd54f2fa343cdf8bb69ec020598
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-observed-and-objectlink.md
@@ -0,0 +1,382 @@
+# \@Observed和\@ObjectLink:嵌套类对象属性变化
+
+
+上文所述的装饰器仅能观察到第一层的变化,但是在实际应用开发中,应用会根据开发需要,封装自己的数据模型。对于多层嵌套的情况,比如二维数组,或者数组项class,或者class的属性是class,他们的第二层的属性变化是无法观察到的。这就引出了\@Observed/\@ObjectLink装饰器。
+
+
+> **说明:**
+> 从API version 9开始,这两个装饰器支持在ArkTS卡片中使用。
+
+
+## 概述
+
+\@ObjectLink和\@Observed类装饰器用于在涉及嵌套对象或数组的场景中进行双向数据同步:
+
+- 被\@Observed装饰的类,可以被观察到属性的变化;
+
+- 子组件中\@ObjectLink装饰器装饰的状态变量用于接受\@Observed装饰的类的实例,和父组件中对应的状态变量建立双向数据绑定。这个实例可以是数组中的被\@Observed装饰的项,或者是class object中是属性,这个属性同样也需要被\@Observed装饰。
+
+- 单独使用\@Observed是没有任何作用的,需要搭配\@ObjectLink或者[\@Prop](arkts-prop.md)使用。
+
+
+## 装饰器说明
+
+| \@Observed类装饰器 | 说明 |
+| -------------- | --------------------------------- |
+| 装饰器参数 | 无 |
+| 类装饰器 | 装饰class。需要放在class的定义前,使用new创建类对象。 |
+
+| \@ObjectLink变量装饰器 | 说明 |
+| ----------------- | ---------------------------------------- |
+| 装饰器参数 | 无 |
+| 同步类型 | 不与父组件中的任何类型同步变量。 |
+| 允许装饰的变量类型 | 必须为被\@Observed装饰的class实例,必须指定类型。
不支持简单类型,可以使用[\@Prop](arkts-prop.md)。
\@ObjectLink的属性是可以改变的,但是变量的分配是不允许的,也就是说这个装饰器装饰变量是只读的,不能被改变。 |
+| 被装饰变量的初始值 | 不允许。 |
+
+\@ObjectLink装饰的数据为可读示例。
+
+
+```ts
+// 允许@ObjectLink装饰的数据属性赋值
+this.objLink.a= ...
+// 不允许@ObjectLink装饰的数据自身赋值
+this.objLink= ...
+```
+
+> **说明:**
+>
+> \@ObjectLink装饰的变量不能被赋值,如果要使用赋值操作,请使用[@Prop](arkts-prop.md)。
+>
+> - \@Prop装饰的变量和数据源的关系是是单向同步,\@Prop装饰的变量在本地拷贝了数据源,所以它允许本地更改,如果父组件中的数据源有更新,\@Prop装饰的变量本地的修改将被覆盖;
+>
+> - \@ObjectLink装饰的变量和数据源的关系是双向同步,\@ObjectLink装饰的变量相当于指向数据源的指针。如果一旦发生\@ObjectLink装饰的变量的赋值,则同步链将被打断。
+
+
+## 变量的传递/访问规则说明
+
+| \@ObjectLink传递/访问 | 说明 |
+| ----------------- | ---------------------------------------- |
+| 从父组件初始化 | 必须指定。
初始化\@ObjectLink装饰的变量必须同时满足以下场景:
- 类型必须是\@Observed装饰的class。
- 初始化的数值需要是数组项,或者class的属性。
- 同步源的class或者数组必须是\@State,\@Link,\@Provide,\@Consume或者\@ObjectLink装饰的数据。
同步源是数组项的示例请参考[对象数组](#对象数组)。初始化的class的示例请参考[嵌套对象](#嵌套对象)。 |
+| 与源对象同步 | 双向。 |
+| 可以初始化子组件 | 允许,可用于初始化常规变量、\@State、\@Link、\@Prop、\@Provide |
+
+
+ **图1** 初始化规则图示
+
+
+
+
+
+## 观察变化和行为表现
+
+
+### 观察的变化
+
+\@Observed装饰的类,如果其属性为非简单类型,比如class、Object或者数组,也需要被\@Observed装饰,否则将观察不到其属性的变化。
+
+
+```ts
+class ClassA {
+ public c: number;
+
+ constructor(c: number) {
+ this.c = c;
+ }
+}
+
+@Observed
+class ClassB {
+ public a: ClassA;
+ public b: number;
+
+ constructor(a: ClassA, b: number) {
+ this.a = a;
+ this.b = b;
+ }
+}
+```
+
+以上示例中,ClassB被\@Observed装饰,其成员变量的赋值的变化是可以被观察到的,但对于ClassA,没有被\@Observed装饰,其属性的修改不能被观察到。
+
+
+```ts
+@ObjectLink b: ClassB
+
+// 赋值变化可以被观察到
+this.b.a = new ClassA(5)
+this.b.b = 5
+
+// ClassA没有被@Observed装饰,其属性的变化观察不到
+this.b.a.c = 5
+```
+
+\@ObjectLink:\@ObjectLink只能接受被\@Observed装饰class的实例,可以观察到:
+
+- 其属性的数值的变化,其中属性是指Object.keys(observedObject)返回的所有属性,示例请参考[嵌套对象](#嵌套对象)。
+
+- 如果数据源是数组,则可以观察到数组item的替换,如果数据源是class,可观察到class的属性的变化,示例请参考[对象数组](#对象数组)。
+
+
+### 框架行为
+
+1. 初始渲染:
+ 1. \@Observed装饰的class的实例会被不透明的代理对象包装,代理了class上的属性的setter和getter方法
+ 2. 子组件中\@ObjectLink装饰的从父组件初始化,接受被\@Observed装饰的class的实例,\@ObjectLink的包装类会将自己注册给\@Observed class。
+
+2. 属性更新:当\@Observed装饰的class属性改变时,会走到代理的setter和getter,然后遍历依赖它的\@ObjectLink包装类,通知数据更新。
+
+
+## 使用场景
+
+
+### 嵌套对象
+
+以下是嵌套类对象的数据结构。
+
+
+```ts
+// objectLinkNestedObjects.ets
+let NextID: number = 1;
+
+@Observed
+class ClassA {
+ public id: number;
+ public c: number;
+
+ constructor(c: number) {
+ this.id = NextID++;
+ this.c = c;
+ }
+}
+
+@Observed
+class ClassB {
+ public a: ClassA;
+
+ constructor(a: ClassA) {
+ this.a = a;
+ }
+}
+```
+
+
+ 以下组件层次结构呈现的是此数据结构
+
+```ts
+@Component
+struct ViewA {
+ label: string = 'ViewA1';
+ @ObjectLink a: ClassA;
+
+ build() {
+ Row() {
+ Button(`ViewA [${this.label}] this.a.c=${this.a.c} +1`)
+ .onClick(() => {
+ this.a.c += 1;
+ })
+ }
+ }
+}
+
+@Entry
+@Component
+struct ViewB {
+ @State b: ClassB = new ClassB(new ClassA(0));
+
+ build() {
+ Column() {
+ ViewA({ label: 'ViewA #1', a: this.b.a })
+ ViewA({ label: 'ViewA #2', a: this.b.a })
+
+ Button(`ViewB: this.b.a.c+= 1`)
+ .onClick(() => {
+ this.b.a.c += 1;
+ })
+ Button(`ViewB: this.b.a = new ClassA(0)`)
+ .onClick(() => {
+ this.b.a = new ClassA(0);
+ })
+ Button(`ViewB: this.b = new ClassB(ClassA(0))`)
+ .onClick(() => {
+ this.b = new ClassB(new ClassA(0));
+ })
+ }
+ }
+}
+```
+
+
+ViewB中的事件句柄:
+
+
+- this.b.a = new ClassA(0) 和this.b = new ClassB(new ClassA(0)): 对\@State装饰的变量b和其属性的修改。
+
+- this.b.a.c = ... :该变化属于第二次的变化,[@State](arkts-state.md#观察变化)无法观察到第二层的变化,但是ClassA被\@Observed装饰,ClassA的属性c的变化可以被\@ObjectLink观察到。
+
+
+ViewA中的事件句柄:
+
+
+- this.a.c += 1:对\@ObjectLink变量a的修改,将触发Button组件的刷新。\@ObjectLink和\@Prop不同,\@ObjectLink不拷贝来自父组件的数据源,而是在本地构建了指向其数据源的引用。
+
+- \@ObjectLink变量是只读的,this.a = new ClassA(...)是不允许的,因为一旦赋值操作发生,指向数据源的引用将被重置,同步将被打断。
+
+
+### 对象数组
+
+对象数组是一种常用的数据结构。以下示例展示了数组对象的用法。
+
+
+```ts
+@Component
+struct ViewA {
+ // 子组件ViewA的@ObjectLink的类型是ClassA
+ @ObjectLink a: ClassA;
+ label: string = 'ViewA1';
+
+ build() {
+ Row() {
+ Button(`ViewA [${this.label}] this.a.c = ${this.a.c} +1`)
+ .onClick(() => {
+ this.a.c += 1;
+ })
+ }
+ }
+}
+
+@Entry
+@Component
+struct ViewB {
+ // ViewB中有@State装饰的ClassA[]
+ @State arrA: ClassA[] = [new ClassA(0), new ClassA(0)];
+
+ build() {
+ Column() {
+ ForEach(this.arrA,
+ (item) => {
+ ViewA({ label: `#${item.id}`, a: item })
+ },
+ (item) => item.id.toString()
+ )
+ // 使用@State装饰的数组的数组项初始化@ObjectLink,其中数组项是被@Observed装饰的ClassA的实例
+ ViewA({ label: `ViewA this.arrA[first]`, a: this.arrA[0] })
+ ViewA({ label: `ViewA this.arrA[last]`, a: this.arrA[this.arrA.length-1] })
+
+ Button(`ViewB: reset array`)
+ .onClick(() => {
+ this.arrA = [new ClassA(0), new ClassA(0)];
+ })
+ Button(`ViewB: push`)
+ .onClick(() => {
+ this.arrA.push(new ClassA(0))
+ })
+ Button(`ViewB: shift`)
+ .onClick(() => {
+ this.arrA.shift()
+ })
+ Button(`ViewB: chg item property in middle`)
+ .onClick(() => {
+ this.arrA[Math.floor(this.arrA.length / 2)].c = 10;
+ })
+ Button(`ViewB: chg item property in middle`)
+ .onClick(() => {
+ this.arrA[Math.floor(this.arrA.length / 2)] = new ClassA(11);
+ })
+ }
+ }
+}
+```
+
+- this.arrA[Math.floor(this.arrA.length/2)] = new ClassA(..) :该状态变量的改变触发2次更新:
+ 1. ForEach:数组项的赋值导致ForEach的[itemGenerator](arkts-rendering-control-foreach.md#接口描述)被修改,因此数组项被识别为有更改,ForEach的item builder将执行,创建新的ViewA组件实例。
+ 2. ViewA({ label: `ViewA this.arrA[first]`, a: this.arrA[0] }):上述更改改变了数组中第一个元素,所以绑定this.arrA[0]的ViewA将被更新;
+
+- this.arrA.push(new ClassA(0)) : 将触发2次不同效果的更新:
+ 1. ForEach:新添加的ClassA对象对于ForEach是未知的[itemGenerator](arkts-rendering-control-foreach.md#接口描述),ForEach的item builder将执行,创建新的ViewA组件实例。
+ 2. ViewA({ label: `ViewA this.arrA[last]`, a: this.arrA[this.arrA.length-1] }):数组的最后一项有更改,因此引起第二个ViewA的实例的更改。对于ViewA({ label: `ViewA this.arrA[first]`, a: this.arrA[0] }),数组的更改并没有触发一个数组项更改的改变,所以第一个ViewA不会刷新。
+
+- this.arrA[Math.floor(this.arrA.length/2)].c:[@State](arkts-state.md#观察变化)无法观察到第二层的变化,但是ClassA被\@Observed装饰,ClassA的属性的变化将被\@ObjectLink观察到。
+
+
+### 二维数组
+
+使用\@Observed观察二维数组的变化。可以声明一个被\@Observed装饰的继承Array的子类。
+
+
+```ts
+@Observed
+class StringArray extends Array {
+}
+```
+
+使用new StringArray()来构造StringArray的实例,new运算符使得\@Observed生效,\@Observed观察到StringArray的属性变化。
+
+声明一个从Array扩展的类class StringArray extends Array<String> {},并创建StringArray的实例。\@Observed装饰的类需要使用new运算符来构建class实例。
+
+
+```ts
+@Observed
+class StringArray extends Array {
+}
+
+@Component
+struct ItemPage {
+ @ObjectLink itemArr: StringArray;
+
+ build() {
+ Row() {
+ Text('ItemPage')
+ .width(100).height(100)
+
+ ForEach(this.itemArr,
+ item => {
+ Text(item)
+ .width(100).height(100)
+ },
+ item => item
+ )
+ }
+ }
+}
+
+@Entry
+@Component
+struct IndexPage {
+ @State arr: Array = [new StringArray(), new StringArray(), new StringArray()];
+
+ build() {
+ Column() {
+ ItemPage({ itemArr: this.arr[0] })
+ ItemPage({ itemArr: this.arr[1] })
+ ItemPage({ itemArr: this.arr[2] })
+
+ Divider()
+
+ ForEach(this.arr,
+ itemArr => {
+ ItemPage({ itemArr: itemArr })
+ },
+ itemArr => itemArr[0]
+ )
+
+ Divider()
+
+ Button('update')
+ .onClick(() => {
+ console.error('Update all items in arr');
+ if (this.arr[0][0] !== undefined) {
+ // 正常情况下需要有一个真实的ID来与ForEach一起使用,但此处没有
+ // 因此需要确保推送的字符串是唯一的。
+ this.arr[0].push(`${this.arr[0].slice(-1).pop()}${this.arr[0].slice(-1).pop()}`);
+ this.arr[1].push(`${this.arr[1].slice(-1).pop()}${this.arr[1].slice(-1).pop()}`);
+ this.arr[2].push(`${this.arr[2].slice(-1).pop()}${this.arr[2].slice(-1).pop()}`);
+ } else {
+ this.arr[0].push('Hello');
+ this.arr[1].push('World');
+ this.arr[2].push('!');
+ }
+ })
+ }
+ }
+}
+```
diff --git a/zh-cn/application-dev/quick-start/arkts-other-state-mgmt-functions-overview.md b/zh-cn/application-dev/quick-start/arkts-other-state-mgmt-functions-overview.md
new file mode 100644
index 0000000000000000000000000000000000000000..f47b542b64e8f56be9986970fdc55bd02c8b5906
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-other-state-mgmt-functions-overview.md
@@ -0,0 +1,9 @@
+# 其他状态管理概述
+
+
+除了前面章节提到的组件状态管理和应用状态管理,ArkTS还提供了\@Watch和$$来为开发者提供更多功能:
+
+
+- \@Watch用于监听状态变量的变化。
+
+- $$运算符:给内置组件提供TS变量的引用,使得TS变量和内置组件的内部状态保持同步。
diff --git a/zh-cn/application-dev/quick-start/arkts-page-custom-components-lifecycle.md b/zh-cn/application-dev/quick-start/arkts-page-custom-components-lifecycle.md
new file mode 100644
index 0000000000000000000000000000000000000000..01432b784c0432abcfa6c994dcdaaeeafd4fb673
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-page-custom-components-lifecycle.md
@@ -0,0 +1,186 @@
+# 页面和自定义组件生命周期
+
+
+在开始之前,我们先明确自定义组件和页面的关系:
+
+
+- 自定义组件:\@Component装饰的UI单元,可以组合多个系统组件实现UI的复用。
+
+- 页面:即应用的UI页面。可以由一个或者多个自定义组件组成,\@Entry装饰的自定义组件为页面的入口组件,即页面的根节点,一个页面有且仅能有一个\@Entry。只有被\@Entry装饰的组件才可以调用页面的生命周期。
+
+
+页面生命周期,即被\@Entry装饰的组件生命周期,提供以下生命周期接口:
+
+
+- [onPageShow](../reference/arkui-ts/ts-custom-component-lifecycle.md#onpageshow):页面每次显示时触发。
+
+- [onPageHide](../reference/arkui-ts/ts-custom-component-lifecycle.md#onpagehide):页面每次隐藏时触发一次。
+
+- [onBackPress](../reference/arkui-ts/ts-custom-component-lifecycle.md#onbackpress):当用户点击返回按钮时触发。
+
+
+组件生命周期,即一般用\@Component装饰的自定义组件,提供以下生命周期接口:
+
+
+- [aboutToAppear](../reference/arkui-ts/ts-custom-component-lifecycle.md#abouttoappear):组件即将出现时回调该接口,具体时机为在创建自定义组件的新实例后,在执行其build()函数之前执行。
+
+- [aboutToDisappear](../reference/arkui-ts/ts-custom-component-lifecycle.md#abouttodisappear):在自定义组件即将析构销毁时执行。
+
+
+生命周期流程如下图所示,下图展示的是被\@Entry装饰的组件(首页)生命周期。
+
+
+
+
+
+根据上面的流程图,我们从自定义组件的初始创建、重新渲染和删除来详细解释。
+
+
+## 自定义组件的创建和渲染流程
+
+1. 自定义组件的创建:自定义组件的实例由ArkUI框架创建。
+
+2. 初始化自定义组件的成员变量:通过本地默认值或者构造方法传递参数来初始化自定义组件的成员变量,初始化顺序为成员变量的定义顺序。
+
+3. 如果开发者定义了aboutToAppear,则执行aboutToAppear方法。
+
+4. 在首次渲染的时候,执行build方法渲染系统组件,如果有自定义子组件,则创建自定义组件的实例。在执行build()函数的过程中,框架会观察每个状态变量的读取状态,将保存两个map:
+ 1. 状态变量 -> UI组件(包括ForEach和if)。
+ 2. UI组件 -> 此组件的更新函数,即一个lambda方法,作为build()函数的子集,创建对应的UI组件并执行其属性方法,示意如下。
+
+
+ ```ts
+ build() {
+ ...
+ this.observeComponentCreation(() => {
+ Button.create();
+ })
+
+ this.observeComponentCreation(() => {
+ Text.create();
+ })
+ ...
+ }
+ ```
+
+
+当应用在后台启动时,此时应用进程并没有销毁,所以仅需要执行onPageShow。
+
+
+## 自定义组件重新渲染
+
+当事件句柄被触发(比如设置了点击事件,即触发点击事件)改变了状态变量时,或者LocalStorage / AppStorage中的属性更改,并导致绑定的状态变量更改其值时:
+
+
+1. 框架观察到了变化,将启动重新渲染。
+
+2. 根据框架持有的两个map(自定义组件的创建和渲染流程中第4步),框架可以知道该状态变量管理了哪些UI组件,以及这些UI组件对应的更新函数。执行这些UI组件的更新函数,实现最小化更新。
+
+
+## 自定义组件的删除
+
+如果if组件的分支改变,或者ForEach循环渲染中数组的个数改变,组件将被删除:
+
+
+1. 在删除组件之前,将调用其aboutToDisappear生命周期函数,标记着该节点将要被销毁。ArkUI的节点删除机制是:后端节点直接从组件树上摘下,后端节点被销毁,对前端节点解引用,当前端节点已经没有引用时,将被JS虚拟机垃圾回收。
+
+2. 自定义组件和它的变量将被删除,如果其有同步的变量,比如[@Link](arkts-link.md)、[@Prop](zh-cn_topic_0000001524296665.xml)、[@StorageLink](arkts-appstorage.md#storagelink),将从[同步源](arkts-state-management-overview.md#基本概念)上取消注册。
+
+
+不建议在生命周期aboutToDisappear内使用async await,如果在生命周期的aboutToDisappear使用异步操作(Promise或者回调方法),自定义组件将被保留在Promise的闭包中,直到回调方法被执行完,这个行为阻止了自定义组件的垃圾回收。
+
+
+以下示例展示了生命周期的调用时机:
+
+
+
+```ts
+// Index.ets
+import router from '@ohos.router';
+
+@Entry
+@Component
+struct MyComponent {
+ @State showChild: boolean = true;
+
+ // 只有被@Entry装饰的组件才可以调用页面的生命周期
+ onPageShow() {
+ console.info('Index onPageShow');
+ }
+ // 只有被@Entry装饰的组件才可以调用页面的生命周期
+ onPageHide() {
+ console.info('Index onPageHide');
+ }
+
+ // 只有被@Entry装饰的组件才可以调用页面的生命周期
+ onBackPress() {
+ console.info('Index onBackPress');
+ }
+
+ // 组件生命周期
+ aboutToAppear() {
+ console.info('MyComponent aboutToAppear');
+ }
+
+ // 组件生命周期
+ aboutToDisappear() {
+ console.info('MyComponent aboutToDisappear');
+ }
+
+ build() {
+ Column() {
+ // this.showChild为true,创建Child子组件,执行Child aboutToAppear
+ if (this.showChild) {
+ Child()
+ }
+ // this.showChild为false,删除Child子组件,执行Child aboutToDisappear
+ Button('create or delete Child').onClick(() => {
+ this.showChild = false;
+ })
+ // push到Page2页面,执行onPageHide
+ Button('push to next page')
+ .onClick(() => {
+ router.pushUrl({ url: 'pages/Page2' });
+ })
+ }
+
+ }
+}
+
+@Component
+struct Child {
+ @State title: string = 'Hello World';
+ // 组件生命周期
+ aboutToDisappear() {
+ console.info('[lifeCycle] Child aboutToDisappear')
+ }
+ // 组件生命周期
+ aboutToAppear() {
+ console.info('[lifeCycle] Child aboutToAppear')
+ }
+
+ build() {
+ Text(this.title).fontSize(50).onClick(() => {
+ this.title = 'Hello ArkUI';
+ })
+ }
+}
+```
+
+
+以上示例中,Index页面包含两个自定义组件,一个是被\@Entry装饰的MyComponent,也是页面的入口组件,即页面的根节点;一个是Child,是MyComponent的子组件。只有\@Entry装饰的节点才可以生效页面的生命周期方法,所以MyComponent中声明了当前Index页面的页面生命周期函数。MyComponent和其子组件Child也同时也声明了组件的生命周期函数。
+
+
+- 应用冷启动的初始化流程为:MyComponent aboutToAppear --> MyComponent build --> Child aboutToAppear --> Child build --> Child build执行完毕 --> MyComponent build执行完毕 --> Index onPageShow。
+
+- 点击“delete Child”,if绑定的this.showChild变成false,删除Child组件,会执行Child aboutToDisappear方法。
+
+
+- 点击“push to next page”,调用router.pushUrl接口,跳转到另外一个页面,当前Index页面隐藏,执行页面生命周期Index onPageHide。此处调用的是router.pushUrl接口,Index页面被隐藏,并没有销毁,所以只调用onPageHide。跳转到新页面后,执行初始化新页面的生命周期的流程。
+
+- 如果调用的是router.replaceUrl,则当前Index页面被销毁,执行的生命周期流程将变为:Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。上文已经提到,组件的销毁是从组件树上直接摘下子树,所以先调用父组件的aboutToDisappear,再调用子组件的aboutToDisAppear,然后执行初始化新页面的生命周期流程。
+
+- 点击返回按钮,触发页面生命周期Index onBackPress。最小化应用或者应用进入后台,触发Index onPageHide。这两个状态下应用都没有被销毁,所以并不会执行组件的aboutToDisappear 。应用回到前台,执行Index onPageShow。
+
+
+- 退出应用,执行Index onPageHide --> MyComponent aboutToDisappear --> Child aboutToDisappear。
diff --git a/zh-cn/application-dev/quick-start/arkts-persiststorage.md b/zh-cn/application-dev/quick-start/arkts-persiststorage.md
new file mode 100644
index 0000000000000000000000000000000000000000..a50cbe24ed891c59250e206ccfa291da2c974481
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-persiststorage.md
@@ -0,0 +1,114 @@
+# PersistentStorage:持久化存储UI状态
+
+
+前两个小节介绍的LocalStorage和AppStorage都是运行时的内存,但是在应用退出再次启动后,依然能保存选定的结果,是应用开发中十分常见的现象,这就需要用到PersistentStorage。
+
+
+PersistentStorage是应用程序中的可选单例对象。此对象的作用是持久化存储选定的AppStorage属性,以确保这些属性在应用程序重新启动时的值与应用程序关闭时的值相同。
+
+
+## 概述
+
+PersistentStorage将选定的AppStorage属性保留在设备磁盘上。应用程序通过API,以决定哪些AppStorage属性应借助PersistentStorage持久化。UI和业务逻辑不直接访问PersistentStorage中的属性,所有属性访问都是对AppStorage的访问,AppStorage中的更改会自动同步到PersistentStorage。
+
+PersistentStorage和AppStorage中的属性建立双向同步。应用开发通常通过AppStorage访问PersistentStorage,另外还有一些接口可以用于管理持久化属性,但是业务逻辑始终是通过AppStorage获取和设置属性的。
+
+
+## 限制条件
+
+持久化数据是一个相对缓慢的操作,应用程序应避免以下情况:
+
+- 持久化大型数据集。
+
+- 持久化经常变化的变量。
+
+当持久化更改的过程变得太繁重时,PersistentStorage实现可能会限制持久化属性更改的频率。
+
+
+## 使用场景
+
+
+### 从AppStorage中访问PersistentStorage初始化的属性
+
+1. 初始化PersistentStorage:
+
+ ```ts
+ PersistentStorage.PersistProp('aProp', 47);
+ ```
+
+2. 在AppStorage获取对应属性:
+
+ ```ts
+ AppStorage.Get('aProp'); // returns 47
+ ```
+
+ 或在组件内部定义:
+
+
+ ```ts
+ @StorageLink('aProp') aProp: number = 48;
+ ```
+
+完整代码如下:
+
+
+```ts
+PersistentStorage.PersistProp('aProp', 47);
+
+@Entry
+@Component
+struct Index {
+ @State message: string = 'Hello World'
+ @StorageLink('aProp') aProp: number = 48
+
+ build() {
+ Row() {
+ Column() {
+ Text(this.message)
+ // 应用退出时会保存当前结果。重新启动后,会显示上一次的保存结果
+ Text(`${this.aProp}`)
+ .onClick(() => {
+ this.aProp += 1;
+ })
+ }
+ }
+ }
+}
+```
+
+- 新应用安装后首次启动运行:
+ 1. 调用PersistProp初始化PersistentStorage,首先查询在PersistentStorage本地文件中是否存在“aProp”,查询结果为不存在,因为应用是第一次安装。;
+ 2. 接着查询属性“aProp”在AppStorage中是否存在,依旧不存在;
+ 3. 在AppStorge中创建名为“aProp”的number类型属性,属性初始值是定义的默认值47;
+ 4. PersistentStorage将属性“aProp”和值47写入磁盘,AppStorage中“aProp”对应的值和其后续的更改将被持久化;
+ 5. 在Index组件中创建状态变量\@StorageLink('aProp') aProp,和AppStorage中“aProp”双向绑定,在创建的过程中会在AppStorage中查找,成功找到“aProp”,所以使用其在AppStorage找到的值47。
+
+ **图1** PersistProp初始化流程
+
+
+
+- 触发点击事件后:
+ 1. 状态变量\@StorageLink('aProp') aProp改变,触发Text组件重新刷新;
+ 2. \@StorageLink装饰的变量是和AppStorage中建立双向同步的,所以\@StorageLink('aProp') aProp的变化会被同步回AppStorage中;
+ 3. AppStorage中“aProp”属性的改变会同步到所有绑定该“aProp”的单向或者双向变量,在本示例中没有其他的绑定“aProp”的变量;
+ 4. 因为“aProp”对应的属性已经被持久化,所以在AppStorage中“aProp”的改变会触发PersistentStorage将新的改变写会本地磁盘。
+
+- 后续启动应用:
+ 1. 执行PersistentStorage.PersistProp('aProp', 47),在首先查询在PersistentStorage本地文件查询“aProp”属性,成功查询到;
+ 2. 将在PersistentStorage查询到的值写入AppStorage中;
+ 3. 在Index组件里,\@StorageLink绑定的“aProp”为PersistentStorage写入AppStorage中的值,即为上一次退出引用存入的值。
+
+
+### 在PersistentStorage之前访问AppStorage中的属性
+
+该示例为反例。在调用PersistentStorage.PersistProp或者PersistProps之前使用接口访问AppStorage中的属性是错误的,因为这样的调用顺序会丢失上一次应用程序运行中的属性值:
+
+
+```ts
+let aProp = AppStorage.SetOrCreate('aProp', 47);
+PersistentStorage.PersistProp('aProp', 48);
+```
+
+应用在非首次运行时,先执行AppStorage.SetOrCreate('aProp', 47):属性“aProp”在AppStorage中创建,其类型为number,其值设置为指定的默认值47。'aProp'是持久化的属性,所以会被写回PersistentStorage磁盘中,PersistentStorage存储的上次退出应用的值丢失。
+
+PersistentStorage.PersistProp('aProp', 48):在PersistentStorage中查找到“aProp”,找到,值为47。
diff --git a/zh-cn/application-dev/quick-start/arkts-prop.md b/zh-cn/application-dev/quick-start/arkts-prop.md
new file mode 100644
index 0000000000000000000000000000000000000000..5a36f3d513d9cf075f0d1dddcc48ac0c19c3dda8
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-prop.md
@@ -0,0 +1,367 @@
+# \@Prop:父子单向同步
+
+
+\@Prop装饰的变量可以和父组件建立单向的同步关系。\@Prop装饰的变量是可变的,但是变化不会同步回其父组件。
+
+
+> **说明:**
+>
+> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+
+## 概述
+
+\@Prop装饰的变量和父组件建立单向的同步关系:
+
+- \@Prop变量允许在本地修改,但修改后的变化不会同步回父组件。
+
+- 当父组件中的数据源更改时,与之相关的\@Prop装饰的变量都会自动更新。如果子组件已经在本地修改了\@Prop装饰的相关变量值,而在父组件中对应的\@State装饰的变量被修改后,子组件本地修改的\@Prop装饰的相关变量值将被覆盖。
+
+
+## 装饰器使用规则说明
+
+| \@Prop变量装饰器 | 说明 |
+| ----------- | ---------------------------------------- |
+| 装饰器参数 | 无 |
+| 同步类型 | 单向同步:对父组件状态变量值的修改,将同步给子组件\@Prop装饰的变量,子组件\@Prop变量的修改不会同步到父组件的状态变量上 |
+| 允许装饰的变量类型 | string、number、boolean、enum类型。
不支持any,不允许使用undefined和null。
必须指定类型。
在父组件中,传递给\@Prop装饰的值不能为undefined或者null,反例如下所示。
CompA ({ aProp: undefined })
CompA ({ aProp: null })
\@Prop和[数据源](arkts-state-management-overview.md#基本概念)类型需要相同,有以下三种情况(数据源以\@State为例):
- \@Prop装饰的变量和父组件状态变量类型相同,即\@Prop : S和\@State : S,示例请参考[父组件@State到子组件@Prop简单数据类型同步](#父组件state到子组件prop简单数据类型同步)。
- 当父组件的状态变量为数组时,\@Prop装饰的变量和父组件状态变量的数组项类型相同,即\@Prop : S和\@State : Array<S>,示例请参考[父组件@State数组中的项到子组件@Prop简单数据类型同步](#父组件state数组项到子组件prop简单数据类型同步);
- 当父组件状态变量为Object或者class时,\@Prop装饰的变量和父组件状态变量的属性类型相同,即\@Prop : S和\@State : { propA: S },示例请参考[从父组件中的@State类对象属性到@Prop简单类型的同步](#从父组件中的state类对象属性到prop简单类型的同步)。 |
+| 被装饰变量的初始值 | 允许本地初始化。 |
+
+
+## 变量的传递/访问规则说明
+
+| 传递/访问 | 说明 |
+| --------- | ---------------------------------------- |
+| 从父组件初始化 | 如果本地有初始化,则是可选的。没有的话,则必选,支持父组件中的常规变量、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp去初始化子组件中的\@Prop变量。 |
+| 用于初始化子组件 | \@Prop支持去初始化子组件中的常规变量、\@State、\@Link、\@Prop、\@Provide。 |
+| 是否支持组件外访问 | \@Prop装饰的变量是私有的,只能在组件内访问。 |
+
+
+ **图1** 初始化规则图示
+
+
+
+
+
+## 观察变化和行为表现
+
+
+### 观察变化
+
+\@Prop装饰的数据可以观察到以下变化。
+
+- 当装饰的类型是允许的类型,即string、number、boolean、enum类型都可以观察到的赋值变化;
+
+ ```ts
+ // 简单类型
+ @Prop count: number;
+ // 赋值的变化可以被观察到
+ this.count = 1;
+ ```
+
+对于\@State和\@Prop的同步场景:
+
+- 使用父组件中\@State变量的值初始化子组件中的\@Prop变量。当\@State变量变化时,该变量值也会同步更新至\@Prop变量。
+
+- \@Prop装饰的变量的修改不会影响其数据源\@State装饰变量的值。
+
+- 除了\@State,数据源也可以用\@Link或\@Prop装饰,对\@Prop的同步机制是相同的。
+
+- 数据源和\@Prop变量的类型需要相同。
+
+
+### 框架行为
+
+要理解\@Prop变量值初始化和更新机制,有必要了解父组件和拥有\@Prop变量的子组件初始渲染和更新流程。
+
+1. 初始渲染:
+ 1. 执行父组件的build()函数将创建子组件的新实例,将数据源传递给子组件;
+ 2. 初始化子组件\@Prop装饰的变量。
+
+2. 更新:
+ 1. 子组件\@Prop更新时,更新仅停留在当前子组件,不会同步回父组件;
+ 2. 当父组件的数据源更新时,子组件的\@Prop装饰的变量将被来自父组件的数据源重置,所有\@Prop装饰的本地的修改将被父组件的更新覆盖。
+
+
+## 使用场景
+
+
+### 父组件\@State到子组件\@Prop简单数据类型同步
+
+
+以下示例是\@State到子组件\@Prop简单数据同步,父组件ParentComponent的状态变量countDownStartValue初始化子组件CountDownComponent中\@Prop装饰的count,点击“Try again”,count的修改仅保留在CountDownComponent 不会同步给父组件CountDownComponent。
+
+
+ParentComponent的状态变量countDownStartValue的变化将重置CountDownComponent的count。
+
+
+
+```ts
+@Component
+struct CountDownComponent {
+ @Prop count: number;
+ costOfOneAttempt: number = 1;
+
+ build() {
+ Column() {
+ if (this.count > 0) {
+ Text(`You have ${this.count} Nuggets left`)
+ } else {
+ Text('Game over!')
+ }
+ // @Prop装饰的变量不会同步给父组件
+ Button(`Try again`).onClick(() => {
+ this.count -= this.costOfOneAttempt;
+ })
+ }
+ }
+}
+
+@Entry
+@Component
+struct ParentComponent {
+ @State countDownStartValue: number = 10;
+
+ build() {
+ Column() {
+ Text(`Grant ${this.countDownStartValue} nuggets to play.`)
+ // 父组件的数据源的修改会同步给子组件
+ Button(`+1 - Nuggets in New Game`).onClick(() => {
+ this.countDownStartValue += 1;
+ })
+ // 父组件的修改会同步给子组件
+ Button(`-1 - Nuggets in New Game`).onClick(() => {
+ this.countDownStartValue -= 1;
+ })
+
+ CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
+ }
+ }
+}
+```
+
+
+在上面的示例中:
+
+
+1. CountDownComponent子组件首次创建时其\@Prop装饰的count变量将从父组件\@State装饰的countDownStartValue变量初始化;
+
+2. 按“+1”或“-1”按钮时,父组件的\@State装饰的countDownStartValue值会变化,这将触发父组件重新渲染,在父组件重新渲染过程中会刷新使用countDownStartValue状态变量的UI组件并单向同步更新CountDownComponent子组件中的count值;
+
+3. 更新count状态变量值也会触发CountDownComponent的重新渲染,在重新渲染过程中,评估使用count状态变量的if语句条件(this.count > 0),并执行true分支中的使用count状态变量的UI组件相关描述来更新Text组件的UI显示;
+
+4. 当按下子组件CountDownComponent的“Try again”按钮时,其\@Prop变量count将被更改,但是count值的更改不会影响父组件的countDownStartValue值;
+
+5. 父组件的countDownStartValue值会变化时,父组件的修改将覆盖掉子组件CountDownComponent中count本地的修改。
+
+
+### 父组件\@State数组项到子组件\@Prop简单数据类型同步
+
+
+父组件中\@State如果装饰的数组,其数组项也可以初始化\@Prop。以下示例中父组件Index中\@State装饰的数组arr,将其数组项初始化子组件Child中\@Prop装饰的value。
+
+
+
+```ts
+@Component
+struct Child {
+ @Prop value: number;
+
+ build() {
+ Text(`${this.value}`)
+ .fontSize(50)
+ .onClick(()=>{this.value++})
+ }
+}
+
+@Entry
+@Component
+struct Index {
+ @State arr: number[] = [1,2,3];
+
+ build() {
+ Row() {
+ Column() {
+ Child({value: this.arr[0]})
+ Child({value: this.arr[1]})
+ Child({value: this.arr[2]})
+
+ Divider().height(5)
+
+ ForEach(this.arr,
+ item => {
+ Child({value: item})
+ },
+ item => item.toString()
+ )
+ Text('replace entire arr')
+ .fontSize(50)
+ .onClick(()=>{
+ // 两个数组都包含项“3”。
+ this.arr = this.arr[0] == 1 ? [3,4,5] : [1,2,3];
+ })
+ }
+ }
+ }
+}
+```
+
+
+初始渲染创建6个子组件实例,每个\@Prop装饰的变量初始化都在本地拷贝了一份数组项。子组件onclick事件处理程序会更改局部变量值。
+
+
+假设我们点击了多次,所有变量的本地取值都是“7”。
+
+
+
+```
+7
+7
+7
+----
+7
+7
+7
+```
+
+
+单击replace entire arr后,屏幕将显示以下信息。
+
+
+
+```
+3
+4
+5
+----
+7
+4
+5
+```
+
+
+- 在子组件Child中做的所有的修改都不会同步回父组件Index组件,所以即使6个组件显示都为7,但在父组件Index中,this.arr保存的值依旧是[1,2,3]。
+
+- 点击replace entire arr,this.arr[0] == 1成立,将this.arr赋值为[3, 4, 5];
+
+- 因为this.arr[0]已更改,Child({value: this.arr[0]})组件将this.arr[0]更新同步到实例\@Prop装饰的变量。Child({value: this.arr[1]})和Child({value: this.arr[2]})的情况也类似。
+
+
+- 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”。
+
+
+### 从父组件中的\@State类对象属性到\@Prop简单类型的同步
+
+如果图书馆有一本图书和两位用户,每位用户都可以将图书标记为已读,此标记行为不会影响其它读者用户。从代码角度讲,对\@Prop图书对象的本地更改不会同步给图书馆组件中的\@State图书对象。
+
+
+```ts
+class Book {
+ public title: string;
+ public pages: number;
+ public readIt: boolean = false;
+
+ constructor(title: string, pages: number) {
+ this.title = title;
+ this.pages = pages;
+ }
+}
+
+@Component
+struct ReaderComp {
+ @Prop title: string;
+ @Prop readIt: boolean;
+
+ build() {
+ Row() {
+ Text(this.title)
+ Text(`... ${this.readIt ? 'I have read' : 'I have bot read it'}`)
+ .onClick(() => this.readIt = true)
+ }
+ }
+}
+
+@Entry
+@Component
+struct Library {
+ @State book: Book = new Book('100 secrets of C++', 765);
+
+ build() {
+ Column() {
+ ReaderComp({ title: this.book.title, readIt: this.book.readIt })
+ ReaderComp({ title: this.book.title, readIt: this.book.readIt })
+ }
+ }
+}
+```
+
+
+### \@Prop本地初始化不和父组件同步
+
+为了支持\@Component装饰的组件复用场景,\@Prop支持本地初始化,这样可以让\@Prop是否与父组件建立同步关系变得可选。当且仅当\@Prop有本地初始化时,从父组件向子组件传递\@Prop的数据源才是可选的。
+
+下面的示例中,子组件包含两个\@Prop变量:
+
+- \@Prop customCounter没有本地初始化,所以需要父组件提供数据源去初始化\@Prop,并当父组件的数据源变化时,\@Prop也将被更新;
+
+- \@Prop customCounter2有本地初始化,在这种情况下,\@Prop依旧允许但非强制父组件同步数据源给\@Prop。
+
+
+```ts
+@Component
+struct MyComponent {
+ @Prop customCounter: number;
+ @Prop customCounter2: number = 5;
+
+ build() {
+ Column() {
+ Row() {
+ Text(`From Main: ${this.customCounter}`).width(90).height(40).fontColor('#FF0010')
+ }
+
+ Row() {
+ Button('Click to change locally !').width(480).height(60).margin({ top: 10 })
+ .onClick(() => {
+ this.customCounter2++
+ })
+ }.height(100).width(480)
+
+ Row() {
+ Text(`Custom Local: ${this.customCounter2}`).width(90).height(40).fontColor('#FF0010')
+ }
+ }
+ }
+}
+
+@Entry
+@Component
+struct MainProgram {
+ @State mainCounter: number = 10;
+
+ build() {
+ Column() {
+ Row() {
+ Column() {
+ Button('Click to change number').width(480).height(60).margin({ top: 10, bottom: 10 })
+ .onClick(() => {
+ this.mainCounter++
+ })
+ }
+ }
+
+ Row() {
+ Column(
+ // customCounter必须从父组件初始化,因为MyComponent的customCounter成员变量缺少本地初始化;此处,customCounter2可以不做初始化。
+ MyComponent({ customCounter: this.mainCounter })
+ // customCounter2也可以从父组件初始化,父组件初始化的值会覆盖子组件customCounter2的本地初始化的值
+ MyComponent({ customCounter: this.mainCounter, customCounter2: this.mainCounter })
+ }.width('40%')
+ }
+
+ Row() {
+ Text('').width(480).height(10)
+ }
+ }
+ }
+}
+```
diff --git a/zh-cn/application-dev/quick-start/arkts-provide-and-consume.md b/zh-cn/application-dev/quick-start/arkts-provide-and-consume.md
new file mode 100644
index 0000000000000000000000000000000000000000..f0b2f76a1b188a93742f26a04c54be00c44199fa
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-provide-and-consume.md
@@ -0,0 +1,171 @@
+# \@Provide和\@Consume:与后代组件双向同步
+
+
+\@Provide和\@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,\@Provide和\@Consume摆脱参数传递机制的束缚,实现跨层级传递。
+
+
+其中\@Provide装饰的变量是在祖先节点中,可以理解为被“提供”给后代的状态变量。\@Consume装饰的变量是在后代组件中,去“消费(绑定)”祖先节点提供的变量。
+
+
+> **说明:**
+>
+> 从API version 9开始,这两个装饰器支持在ArkTS卡片中使用。
+
+
+## 概述
+
+\@Provide/\@Consume装饰的状态变量有以下特性:
+
+- \@Provide装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,\@Provide的方便之处在于,开发者不需要多次在组件之间传递变量。
+
+- 后代通过使用\@Consume去获取\@Provide提供的变量,建立在\@Provide和\@Consume之间的双向数据同步,与\@State/\@Link不同的是,前者可以在多层级的父子组件之间传递。
+
+- \@Provide和\@Consume可以通过相同的变量名或者相同的变量别名绑定,变量类型必须相同。
+
+
+```ts
+// 通过相同的变量名绑定
+@Provide a: number = 0;
+@Consume a: number;
+
+// 通过相同的变量别名绑定
+@Provide('a') b: number = 0;
+@Consume('a') c: number;
+```
+
+
+\@Provide和\@Consume通过相同的变量名或者相同的变量别名绑定时,\@Provide修饰的变量和\@Consume修饰的变量是一对多的关系。不允许在同一个自定义组件内,包括其子组件中声明多个同名或者同别名的\@Provide装饰的变量。
+
+
+## 装饰器说明
+
+\@State的规则同样适用于\@Provide,差异为\@Provide还作为多层后代的同步源。
+
+| \@Provide变量装饰器 | 说明 |
+| -------------- | ---------------------------------------- |
+| 装饰器参数 | 别名:常量字符串,可选。
如果指定了别名,则通过别名来绑定变量;如果未指定别名,则通过变量名绑定变量。 |
+| 同步类型 | 双向同步。
从\@Provide变量到所有\@Consume变量以及相反的方向的数据同步。双向同步的操作与\@State和\@Link的组合相同。 |
+| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考[观察变化](#观察变化)。
不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。
必须指定类型。\@Provide变量的\@Consume变量的类型必须相同。
**说明:**
不支持Length、ResourceStr、ResourceColor类型,Length、ResourceStr、ResourceColor为简单类型和复杂类型的联合类型。 |
+| 被装饰变量的初始值 | 必须指定。 |
+
+| \@Consume变量装饰器 | 说明 |
+| -------------- | ---------------------------------------- |
+| 装饰器参数 | 别名:常量字符串,可选。
如果提供了别名,则必须有\@Provide的变量和其有相同的别名才可以匹配成功;否则,则需要变量名相同才能匹配成功。 |
+| 同步类型 | 双向:从\@Provide变量(具体请参见\@Provide)到所有\@Consume变量,以及相反的方向。双向同步操作与\@State和\@Link的组合相同。 |
+| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考[观察变化](#观察变化)。
不支持any,不允许使用undefined和null。
必须指定类型。\@Provide变量的\@Consume变量的类型必须相同。
**说明:**
- \@Consume装饰的变量,在其父节点或者祖先节点上,必须有对应的属性和别名的\@Provide装饰的变量。 |
+| 被装饰变量的初始值 | 无,禁止本地初始化。 |
+
+
+## 变量的传递/访问规则说明
+
+
+| \@Provide传递/访问 | 说明 |
+| -------------- | ---------------------------------------- |
+| 从父组件初始化和更新 | 可选,允许父组件中常规变量、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp装饰的变量装饰变量初始化子组件\@Provide。 |
+| 用于初始化子组件 | 允许,可用于初始化\@State、\@Link、\@Prop、\@Provide。 |
+| 和父组件同步 | 否。 |
+| 和后代组件同步 | 和\@Consume双向同步。 |
+| 是否支持组件外访问 | 私有,仅可以在所属组件内访问。 |
+
+
+ **图1** \@Provide初始化规则图示
+
+
+
+
+
+| \@Consume传递/访问 | 说明 |
+| -------------- | ---------------------------------------- |
+| 从父组件初始化和更新 | 禁止。通过相同的变量名和alias(别名)从\@Provide初始化。 |
+| 用于初始化子组件 | 允许,可用于初始化\@State、\@Link、\@Prop、\@Provide。 |
+| 和祖先组件同步 | 和\@Provide双向同步。 |
+| 是否支持组件外访问 | 私有,仅可以在所属组件内访问 |
+
+
+ **图2** \@Consume初始化规则图示
+
+
+
+
+
+## 观察变化和行为表现
+
+
+### 观察变化
+
+- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
+
+- 当装饰的数据类型为class或者Object的时候,可以观察到赋值和属性赋值的变化(属性为Object.keys(observedObject)返回的所有属性)。
+
+- 当装饰的对象是array的时候,可以观察到数组的添加、删除、更新数组单元。
+
+
+### 框架行为
+
+1. 初始渲染:
+ 1. \@Provide装饰的变量会以map的形式,传递给当前\@Provide所属组件的所有子组件;
+ 2. 子组件中如果使用\@Consume变量,则会在map中查找是否有该变量名/alias(别名)对应的\@Provide的变量,如果查找不到,框架会抛出JS ERROR;
+ 3. 在初始化\@Consume变量时,和\@State/\@Link的流程类似,\@Consume变量会保存在map中查找到的\@Provide变量,并把自己注册给\@Provide。
+
+2. 当\@Provide装饰的数据变化时:
+ 1. 通过初始渲染的步骤可知,子组件\@Consume已把自己注册给父组件。父组件\@Provide变量变更后,会遍历更新所有依赖它的系统组件(elementid)和状态变量(\@Consume);
+ 2. 通知\@Consume更新后,子组件所有依赖\@Consume的系统组件(elementId)都会被通知更新。以此实现\@Provide对\@Consume状态数据同步。
+
+3. 当\@Consume装饰的数据变化时:
+ 1. 通过初始渲染的步骤可知,子组件\@Consume持有\@Provide的实例。在\@Consume更新后调用\@Provide的更新方法,将更新的数值同步回\@Provide,以此实现\@Consume向\@Provide的同步更新。
+
+
+## 使用场景
+
+在下面的示例是与后代组件双向同步状态\@Provide和\@Consume场景。当分别点击CompA和CompD组件内Button时,reviewVotes 的更改会双向同步在CompA和CompD中。
+
+
+
+```ts
+@Component
+struct CompD {
+ // @Consume装饰的变量通过相同的属性名绑定其祖先组件CompA内的@Provide装饰的变量
+ @Consume reviewVotes: number;
+
+ build() {
+ Column() {
+ Text(`reviewVotes(${this.reviewVotes})`)
+ Button(`reviewVotes(${this.reviewVotes}), give +1`)
+ .onClick(() => this.reviewVotes += 1)
+ }
+ .width('50%')
+ }
+}
+
+@Component
+struct CompC {
+ build() {
+ Row({ space: 5 }) {
+ CompD()
+ CompD()
+ }
+ }
+}
+
+@Component
+struct CompB {
+ build() {
+ CompC()
+ }
+}
+
+@Entry
+@Component
+struct CompA {
+ // @Provide装饰的变量reviewVotes由入口组件CompA提供其后代组件
+ @Provide reviewVotes: number = 0;
+
+ build() {
+ Column() {
+ Button(`reviewVotes(${this.reviewVotes}), give +1`)
+ .onClick(() => this.reviewVotes += 1)
+ CompB()
+ }
+ }
+}
+```
diff --git a/zh-cn/application-dev/quick-start/arkts-rendering-control-foreach.md b/zh-cn/application-dev/quick-start/arkts-rendering-control-foreach.md
new file mode 100644
index 0000000000000000000000000000000000000000..d9caebec07283074b7a647b53c5cd4b3bc866efe
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-rendering-control-foreach.md
@@ -0,0 +1,344 @@
+# ForEach:循环渲染
+
+
+ForEach基于数组类型数据执行循环渲染。
+
+
+## 接口描述
+
+
+```ts
+ForEach(
+ arr: any[],
+ itemGenerator: (item: any, index?: number) => void,
+ keyGenerator?: (item: any, index?: number) => string
+)
+```
+
+
+| 参数名 | 参数类型 | 必填 | 参数描述 |
+| ------------- | ---------------------------------------- | ---- | ---------------------------------------- |
+| arr | Array | 是 | 必须是数组,允许设置为空数组,空数组场景下将不会创建子组件。同时允许设置返回值为数组类型的函数,例如arr.slice(1, 3),设置的函数不得改变包括数组本身在内的任何状态变量,如Array.splice、Array.sort或Array.reverse这些改变原数组的函数。 |
+| itemGenerator | (item: any, index?: number) => void | 是 | 生成子组件的lambda函数,为数组中的每一个数据项创建一个或多个子组件,单个子组件或子组件列表必须包括在大括号“{...}”中。
**说明:**
- 子组件的类型必须是ForEach的父容器组件所允许的(例如,只有当ForEach父级为List组件时,才允许LitemItem子组件)。
- 允许子类构造函数返回if或另一个ForEach。ForEach可以在if内的任意位置。
- 可选index参数如在函数体中使用,则必须仅在函数签名中指定。 |
+| keyGenerator | (item: any, index?: number) => string | 否 | 匿名函数,用于给数组中的每一个数据项生成唯一且固定的键值。键值生成器的功能是可选的,但是,为了使开发框架能够更好地识别数组更改,提高性能,建议提供。如将数组反向时,如果没有提供键值生成器,则ForEach中的所有节点都将重建。
**说明:**
- 同一数组中的不同项绝对不能计算出相同的ID。
- 如果未使用index参数,则项在数组中的位置变动不得改变项的键值。如果使用了index参数,则当项在数组中的位置有变动时,键值必须更改。
- 当某个项目被新项替换(值不同)时,被替换的项键值和新项的键值必须不同。
- 在构造函数中使用index参数时,键值生成函数也必须使用该参数。
- 键值生成函数不允许改变任何组件状态。 |
+
+
+## 使用限制
+
+- ForEach必须在容器组件内使用。
+
+- 生成的子组件应当是允许包含在ForEach父容器组件中的子组件。
+
+- 允许子组件生成器函数中包含if/else条件渲染,同时也允许ForEach包含在if/else条件渲染语句中。
+
+- itemGenerator函数的调用顺序不一定和数组中的数据项相同,在开发过程中不要假设itemGenerator和keyGenerator函数是否执行及其执行顺序。例如,以下示例可能无法正确运行:
+
+ ```ts
+ ForEach(anArray.map((item1, index1) => { return { i: index1 + 1, data: item1 }; }),
+ item => Text(`${item.i}. item.data.label`),
+ item => item.data.id.toString())
+ ```
+
+
+## 开发者的建议
+
+- 建议开发者不要假设项构造函数的执行顺序。执行顺序可能不能是数组中项的排列顺序。
+
+- 不要假设数组项是否是初始渲染。ForEach的初始渲染在\@Component首次渲染时构建所有数组项。后续框架版本中可能会将此行为更改为延迟加载模式。
+
+- 使用 index参数对UI更新性能有严重的负面影响,请尽量避免。
+
+- 如果项构造函数中使用index参数,则项索引函数中也必须使用该参数。否则,如果项索引函数未使用index参数,ForEach在生成实际的键值时,框架也会把index考虑进来,默认将index拼接在后面。
+
+
+## 使用场景
+
+
+### 简单ForEach示例
+
+根据arr数据分别创建3个Text和Divide组件。
+
+
+```ts
+@Entry
+@Component
+struct MyComponent {
+ @State arr: number[] = [10, 20, 30];
+
+ build() {
+ Column({ space: 5 }) {
+ Button('Reverse Array')
+ .onClick(() => {
+ this.arr.reverse();
+ })
+ ForEach(this.arr, (item: number) => {
+ Text(`item value: ${item}`).fontSize(18)
+ Divider().strokeWidth(2)
+ }, (item: number) => item.toString())
+ }
+ }
+}
+```
+
+
+### 复杂ForEach示例
+
+
+```ts
+@Component
+struct CounterView {
+ label: string;
+ @State count: number = 0;
+
+ build() {
+ Button(`${this.label}-${this.count} click +1`)
+ .width(300).height(40)
+ .backgroundColor('#a0ffa0')
+ .onClick(() => {
+ this.count++;
+ })
+ }
+}
+
+@Entry
+@Component
+struct MainView {
+ @State arr: number[] = Array.from(Array(10).keys()); // [0.,.9]
+ nextUnused: number = this.arr.length;
+
+ build() {
+ Column() {
+ Button(`push new item`)
+ .onClick(() => {
+ this.arr.push(this.nextUnused++)
+ })
+ .width(300).height(40)
+ Button(`pop last item`)
+ .onClick(() => {
+ this.arr.pop()
+ })
+ .width(300).height(40)
+ Button(`prepend new item (unshift)`)
+ .onClick(() => {
+ this.arr.unshift(this.nextUnused++)
+ })
+ .width(300).height(40)
+ Button(`remove first item (shift)`)
+ .onClick(() => {
+ this.arr.shift()
+ })
+ .width(300).height(40)
+ Button(`insert at pos ${Math.floor(this.arr.length / 2)}`)
+ .onClick(() => {
+ this.arr.splice(Math.floor(this.arr.length / 2), 0, this.nextUnused++);
+ })
+ .width(300).height(40)
+ Button(`remove at pos ${Math.floor(this.arr.length / 2)}`)
+ .onClick(() => {
+ this.arr.splice(Math.floor(this.arr.length / 2), 1);
+ })
+ .width(300).height(40)
+ Button(`set at pos ${Math.floor(this.arr.length / 2)} to ${this.nextUnused}`)
+ .onClick(() => {
+ this.arr[Math.floor(this.arr.length / 2)] = this.nextUnused++;
+ })
+ .width(300).height(40)
+ ForEach(this.arr,
+ (item) => {
+ CounterView({ label: item.toString() })
+ },
+ (item) => item.toString()
+ )
+ }
+ }
+}
+```
+
+MainView拥有一个\@State装饰的数字数组。添加、删除和替换数组项是可观察到的变化事件,当这些事件发生时,MainView内的ForEach都会更新。
+
+项目索引函数为每个数组项创建唯一且持久的键值,ArkUI框架通过此键值确定数组中的项是否有变化,只要键值相同,数组项的值就假定不变,但其索引位置可能会更改。此机制的运行前提是不同的数组项不能有相同的键值。
+
+使用计算出的ID,框架可以对添加、删除和保留的数组项加以区分:
+
+1. 框架将删除已删除数组项的UI组件。
+
+2. 框架仅对新添加的数组项执行项构造函数。
+
+3. 框架不会为保留的数组项执行项构造函数。如果数组中的项索引已更改,框架将仅根据新顺序移动其UI组件,但不会更新该UI组件。
+
+建议使用项目索引函数,但这是可选的。生成的ID必须是唯一的,这意味着不能为数组中的不同项计算出相同的ID。即使两个数组项具有相同的值,其ID也必须不同。
+
+如果数组项值更改,则ID必须更改。
+如前所述,id生成函数是可选的。以下是不带项索引函数的ForEach:
+
+ ```ts
+ ForEach(this.arr,
+ (item) => {
+ CounterView({ label: item.toString() })
+ }
+ )
+ ```
+
+如果没有提供项ID函数,则框架会尝试在更新ForEach时智能检测数组更改。但是,它可能会删除子组件,并为在数组中移动(索引被更改)的数组项重新执行项构造函数。在上面的示例中,这将更改应用程序针对CounterView counter状态的行为。创建新的CounterView实例时,counter的值将初始化为0。
+
+
+### 使用\@ObjectLink的ForEach示例
+
+当需要保留重复子组件的状态时,\@ObjectLink可将状态在组件树中向父组件推送。
+
+
+```ts
+let NextID: number = 0;
+
+@Observed
+class MyCounter {
+ public id: number;
+ public c: number;
+
+ constructor(c: number) {
+ this.id = NextID++;
+ this.c = c;
+ }
+}
+
+@Component
+struct CounterView {
+ @ObjectLink counter: MyCounter;
+ label: string = 'CounterView';
+
+ build() {
+ Button(`CounterView [${this.label}] this.counter.c=${this.counter.c} +1`)
+ .width(200).height(50)
+ .onClick(() => {
+ this.counter.c += 1;
+ })
+ }
+}
+
+@Entry
+@Component
+struct MainView {
+ @State firstIndex: number = 0;
+ @State counters: Array = [new MyCounter(0), new MyCounter(0), new MyCounter(0),
+ new MyCounter(0), new MyCounter(0)];
+
+ build() {
+ Column() {
+ ForEach(this.counters.slice(this.firstIndex, this.firstIndex + 3),
+ (item) => {
+ CounterView({ label: `Counter item #${item.id}`, counter: item })
+ },
+ (item) => item.id.toString()
+ )
+ Button(`Counters: shift up`)
+ .width(200).height(50)
+ .onClick(() => {
+ this.firstIndex = Math.min(this.firstIndex + 1, this.counters.length - 3);
+ })
+ Button(`counters: shift down`)
+ .width(200).height(50)
+ .onClick(() => {
+ this.firstIndex = Math.max(0, this.firstIndex - 1);
+ })
+ }
+ }
+}
+```
+
+当增加firstIndex的值时,Mainview内的ForEach将更新,并删除与项ID firstIndex-1关联的CounterView子组件。对于ID为firstindex + 3的数组项,将创建新的CounterView子组件实例。由于CounterView子组件的状态变量counter值由父组件Mainview维护,故重建CounterView子组件实例不会重建状态变量counter值。
+
+> **说明:**
+>
+> 违反上述数组项ID规则是最常见的应用开发错误,尤其是在Array<number>场景下,因为执行过程中很容易添加重复的数字。
+
+
+### ForEach的嵌套使用
+
+允许将ForEach嵌套在同一组件中的另一个ForEach中,但更推荐将组件拆分为两个,每个构造函数只包含一个ForEach。下面为ForEach嵌套使用反例。
+
+
+```ts
+class Month {
+ year: number;
+ month: number;
+ days: number[];
+
+ constructor(year: number, month: number, days: number[]) {
+ this.year = year;
+ this.month = month;
+ this.days = days;
+ }
+}
+@Component
+struct CalendarExample {
+ // 模拟6个月
+ @State calendar : Month[] = [
+ new Month(2020, 1, [...Array(31).keys()]),
+ new Month(2020, 2, [...Array(28).keys()]),
+ new Month(2020, 3, [...Array(31).keys()]),
+ new Month(2020, 4, [...Array(30).keys()]),
+ new Month(2020, 5, [...Array(31).keys()]),
+ new Month(2020, 6, [...Array(30).keys()])
+ ]
+ build() {
+ Column() {
+ Button() {
+ Text('next month')
+ }.onClick(() => {
+ this.calendar.shift()
+ this.calendar.push(new Month(year: 2020, month: 7, days: [...Array(31).keys()]))
+ })
+ ForEach(this.calendar,
+ (item: Month) => {
+ ForEach(item.days,
+ (day : number) => {
+ // 构建日期块
+ },
+ (day : number) => day.toString()
+ )// 内部ForEach
+ },
+ (item: Month) => (item.year * 12 + item.month).toString() // 字段与年和月一起使用,作为月份的唯一ID。
+ )// 外部ForEach
+ }
+ }
+}
+```
+
+以上示例存在两个问题:
+
+1. 代码可读性差。
+
+2. 对于上述的年月份数据的数组结构形式,由于框架无法观察到针对该数组中Month数据结构的改变(比如day数组变化),从而内层的ForEach无法刷新日期显示。
+
+建议应用设计时将Calendar拆分为Year、Month和Day子组件。定义一个“Day”模型类,以保存有关day的信息,并用\@Observed装饰此类。DayView组件利用ObjectLink装饰变量以绑定day数据。对MonthView和Month模型类执行同样的操作。
+
+
+### ForEach中使用可选index参数示例
+
+可以在构造函数和ID生成函数中使用可选的index参数。
+
+
+```ts
+@Entry
+@Component
+struct ForEachWithIndex {
+ @State arr: number[] = [4, 3, 1, 5];
+
+ build() {
+ Column() {
+ ForEach(this.arr,
+ (it, indx) => {
+ Text(`Item: ${indx} - ${it}`)
+ },
+ (it, indx) => {
+ return `${indx} - ${it}`
+ }
+ )
+ }
+ }
+}
+```
+
+必须正确构造ID生成函数。当在项构造函数中使用index参数时,ID生成函数也必须使用index参数,以生成唯一ID和给定源数组项的ID。当数组项在数组中的索引位置发生变化时,其ID会发生变化。
+
+此示例还说明了index参数会造成显著性能下降。即使项在源数组中移动而不做修改,因为索引发生改变,依赖该数组项的UI仍然需要重新渲染。例如,使用索引排序时,数组只需要将ForEach未修改的子UI节点移动到正确的位置,这对于框架来说是一个轻量级操作。而使用索引时,所有子UI节点都需要重新构建,这操作负担要重得多。
diff --git a/zh-cn/application-dev/quick-start/arkts-rendering-control-ifelse.md b/zh-cn/application-dev/quick-start/arkts-rendering-control-ifelse.md
new file mode 100644
index 0000000000000000000000000000000000000000..5a9c98c2792a021b46311c6ee7c3f163caed3a66
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-rendering-control-ifelse.md
@@ -0,0 +1,225 @@
+# if/else:条件渲染
+
+
+ArkTS提供了渲染控制的能力。条件渲染可根据应用的不同状态,使用if、else和else if渲染对应状态下的UI内容。
+
+
+## 使用规则
+
+- 支持if、else和else if语句。
+
+- if、else if后跟随的条件语句可以使用状态变量。
+
+- 允许在容器组件内使用,通过条件渲染语句构建不同的子组件。
+
+- 条件渲染语句在涉及到组件的父子关系时是“透明”的,当父组件和子组件之间存在一个或多个if语句时,必须遵守父组件关于子组件使用的规则。
+
+- 每个分支内部的构建函数必须遵循构建函数的规则,并创建一个或多个组件。无法创建组件的空构建函数会产生语法错误。
+
+- 某些容器组件限制子组件的类型或数量,将条件渲染语句用于这些组件内时,这些限制将同样应用于条件渲染语句内创建的组件。例如,Grid容器组件的子组件仅支持GridItem组件,在Grid内使用条件渲染语句时,条件渲染语句内仅允许使用GridItem组件。
+
+
+## 更新机制
+
+当if、else if后跟随的状态判断中使用的状态变量值变化时,条件渲染语句会进行更新,更新步骤如下:
+
+1. 评估if和else if的状态判断条件,如果分支没有变化,请无需执行以下步骤。如果分支有变化,则执行2、3步骤:
+
+2. 删除此前构建的所有子组件。
+
+3. 执行新分支的构造函数,将获取到的组件添加到if父容器中。如果缺少适用的else分支,则不构建任何内容。
+
+条件可以包括Typescript表达式。对于构造函数中的表达式,此类表达式不得更改应用程序状态。
+
+
+## 使用场景
+
+
+### 使用if进行条件渲染
+
+
+```ts
+@Entry
+@Component
+struct ViewA {
+ @State count: number = 0;
+
+ build() {
+ Column() {
+ Text(`count=${this.count}`)
+
+ if (this.count > 0) {
+ Text(`count is positive`)
+ .fontColor(Color.Green)
+ }
+
+ Button('increase count')
+ .onClick(() => {
+ this.count++;
+ })
+
+ Button('decrease count')
+ .onClick(() => {
+ this.count--;
+ })
+ }
+ }
+}
+```
+
+if语句的每个分支都包含一个构建函数。此类构建函数必须创建一个或多个子组件。在初始渲染时,if语句会执行构建函数,并将生成的子组件添加到其父组件中。
+
+每当if或else if条件语句中使用的状态变量发生变化时,条件语句都会更新并重新评估新的条件值。如果条件值评估发生了变化,这意味着需要构建另一个条件分支。此时ArkUI框架将:
+
+1. 删除所有以前渲染的(早期分支的)组件。
+
+2. 执行新分支的构造函数,将生成的子组件添加到其父组件中。
+
+在以上示例中,如果count从0增加到1,那么if语句更新,条件count > 0将重新评估,评估结果将从false更改为true。因此,将执行条件为真分支的构造函数,创建一个Text组件,并将它添加到父组件Column中。如果后续count更改为0,则Text组件将从Column组件中删除。由于没有else分支,因此不会执行新的构造函数。
+
+
+### if ... else ...语句和子组件状态
+
+以下示例包含if ... else ...语句与拥有\@State装饰变量的子组件。
+
+
+```ts
+@Component
+struct CounterView {
+ @State counter: number = 0;
+ label: string = 'unknown';
+
+ build() {
+ Row() {
+ Text(`${this.label}`)
+ Button(`counter ${this.counter} +1`)
+ .onClick(() => {
+ this.counter += 1;
+ })
+ }
+ }
+}
+
+@Entry
+@Component
+struct MainView {
+ @State toggle: boolean = true;
+
+ build() {
+ Column() {
+ if (this.toggle) {
+ CounterView({ label: 'CounterView #positive' })
+ } else {
+ CounterView({ label: 'CounterView #negative' })
+ }
+ Button(`toggle ${this.toggle}`)
+ .onClick(() => {
+ this.toggle = !this.toggle;
+ })
+ }
+ }
+}
+```
+
+CounterView(label为 'CounterView \#positive')子组件在初次渲染时创建。此子组件携带名为counter的状态变量。当修改CounterView.counter状态变量时,CounterView(label为 'CounterView \#positive')子组件重新渲染时并保留状态变量值。当MainView.toggle状态变量的值更改为false时,MainView父组件内的if语句将更新,随后将删除CounterView(label为 'CounterView \#positive')子组件。与此同时,将创建新的CounterView(label为 'CounterView \#negative')实例。而它自己的counter状态变量设置为初始值0。
+
+>  **说明:**
+> CounterView(label为 'CounterView \#positive')和CounterView(label为 'CounterView \#negative')是同一自定义组件的两个不同实例。if分支的更改,不会更新现有子组件,也不会保留状态。
+
+以下示例展示了条件更改时,若需要保留counter值所做的修改。
+
+
+```
+@Component
+struct CounterView {
+ @Link counter: number;
+ label: string = 'unknown';
+
+ build() {
+ Row() {
+ Text(`${this.label}`)
+ Button(`counter ${this.counter} +1`)
+ .onClick(() => {
+ this.counter += 1;
+ })
+ }
+ }
+}
+
+@Entry
+@Component
+struct MainView {
+ @State toggle: boolean = true;
+ @State counter: number = 0;
+
+ build() {
+ Column() {
+ if (this.toggle) {
+ CounterView({ counter: $counter, label: 'CounterView #positive' })
+ } else {
+ CounterView({ counter: $counter, label: 'CounterView #negative' })
+ }
+ Button(`toggle ${this.toggle}`)
+ .onClick(() => {
+ this.toggle = !this.toggle;
+ })
+ }
+ }
+}
+```
+
+此处,\@State counter变量归父组件所有。因此,当CounterView组件实例被删除时,该变量不会被销毁。CounterView组件通过\@Link装饰器引用状态。状态必须从子级移动到其父级(或父级的父级),以避免在条件内容或重复内容被销毁时丢失状态。
+
+
+### 嵌套if语句
+
+条件语句的嵌套对父组件的相关规则没有影响。
+
+
+```ts
+@Entry
+@Component
+struct CompA {
+ @State toggle: boolean = false;
+ @State toggleColor: boolean = false;
+
+ build() {
+ Column() {
+ Text('Before')
+ .fontSize(15)
+ if (this.toggle) {
+ Text('Top True, positive 1 top')
+ .backgroundColor('#aaffaa').fontSize(20)
+ // 内部if语句
+ if (this.toggleColor) {
+ Text('Top True, Nested True, positive COLOR Nested ')
+ .backgroundColor('#00aaaa').fontSize(15)
+ } else {
+ Text('Top True, Nested False, Negative COLOR Nested ')
+ .backgroundColor('#aaaaff').fontSize(15)
+ }
+ } else {
+ Text('Top false, negative top level').fontSize(20)
+ .backgroundColor('#ffaaaa')
+ if (this.toggleColor) {
+ Text('positive COLOR Nested ')
+ .backgroundColor('#00aaaa').fontSize(15)
+ } else {
+ Text('Negative COLOR Nested ')
+ .backgroundColor('#aaaaff').fontSize(15)
+ }
+ }
+ Text('After')
+ .fontSize(15)
+ Button('Toggle Outer')
+ .onClick(() => {
+ this.toggle = !this.toggle;
+ })
+ Button('Toggle Inner')
+ .onClick(() => {
+ this.toggleColor = !this.toggleColor;
+ })
+ }
+ }
+}
+```
diff --git a/zh-cn/application-dev/quick-start/arkts-rendering-control-lazyforeach.md b/zh-cn/application-dev/quick-start/arkts-rendering-control-lazyforeach.md
new file mode 100644
index 0000000000000000000000000000000000000000..876ae9dd328440fd5816983e3321b61dd92c6b16
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-rendering-control-lazyforeach.md
@@ -0,0 +1,220 @@
+# LazyForEach:数据懒加载
+
+
+LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当LazyForEach在滚动容器中使用了,框架会根据滚动容器可视区域按需创建组件,当组件划出可视区域外时,框架会进行组件销毁回收以降低内存占用。
+
+
+## 接口描述
+
+
+```ts
+LazyForEach(
+ dataSource: IDataSource, // 需要进行数据迭代的数据源
+ itemGenerator: (item: any) => void, // 子组件生成函数
+ keyGenerator?: (item: any) => string // (可选) .键值生成函数
+): void
+interface IDataSource {
+ totalCount(): number; // Get total count of data
+ getData(index: number): any; // Get single data by index
+ registerDataChangeListener(listener: DataChangeListener): void; // Register listener to listening data changes
+ unregisterDataChangeListener(listener: DataChangeListener): void; // Unregister listener
+}
+interface DataChangeListener {
+ onDataReloaded(): void; // Called while data reloaded
+ onDataAdd(index: number): void; // Called while single data added
+ onDataMove(from: number, to: number): void; // Called while single data moved
+ onDataDelete(index: number): void; // Called while single data deleted
+ onDataChange(index: number): void; // Called while single data changed
+}
+```
+
+**参数:**
+
+
+| 参数名 | 参数类型 | 必填 | 参数描述 |
+| ------------- | --------------------------------------- | ---- | ---------------------------------------- |
+| dataSource | IDataSource | 是 | LazyForEach数据源,需要开发者实现相关接口。 |
+| itemGenerator | (item: any) => void | 是 | 子组件生成函数,为数组中的每一个数据项创建一个子组件。
**说明:**
itemGenerator的函数体必须使用大括号{...}。itemGenerator每次迭代只能并且必须生成一个子组件。itemGenerator中可以使用if语句,但是必须保证if语句每个分支都会创建一个相同类型的子组件。itemGenerator中不允许使用ForEach和LazyForEach语句。 |
+| keyGenerator | (item: any) => string | 否 | 键值生成函数,用于给数据源中的每一个数据项生成唯一且固定的键值。当数据项在数组中的位置更改时,其键值不得更改,当数组中的数据项被新项替换时,被替换项的键值和新项的键值必须不同。键值生成器的功能是可选的,但是,为了使开发框架能够更好地识别数组更改,提高性能,建议提供。如将数组反向时,如果没有提供键值生成器,则LazyForEach中的所有节点都将重建。
**说明:**
数据源中的每一个数据项生成的键值不能重复。 |
+
+
+## IDataSource类型说明
+
+
+```ts
+interface IDataSource {
+ totalCount(): number;
+ getData(index: number): any;
+ registerDataChangeListener(listener: DataChangeListener): void;
+ unregisterDataChangeListener(listener: DataChangeListener): void;
+}
+```
+
+| 接口声明 | 参数类型 | 说明 |
+| ---------------------------------------- | ------------------ | ------------------------------------- |
+| totalCount(): number | - | 获得数据总数。 |
+| getData(index: number): any | number | 获取索引值index对应的数据。
index:获取数据对应的索引值 |
+| registerDataChangeListener(listener:DataChangeListener): void | DataChangeListener | 注册数据改变的监听器。
listener:数据变化监听器 |
+| unregisterDataChangeListener(listener:DataChangeListener): void | DataChangeListener | 注销数据改变的监听器。
listener:数据变化监听器 |
+
+
+## DataChangeListener类型说明
+
+
+```ts
+interface DataChangeListener {
+ onDataReloaded(): void;
+ onDataAdded(index: number): void;
+ onDataMoved(from: number, to: number): void;
+ onDataDeleted(index: number): void;
+ onDataChanged(index: number): void;
+ onDataAdd(index: number): void;
+ onDataMove(from: number, to: number): void;
+ onDataDelete(index: number): void;
+ onDataChange(index: number): void;
+}
+```
+
+| 接口声明 | 参数类型 | 说明 |
+| ---------------------------------------- | -------------------------------------- | ---------------------------------------- |
+| onDataReloaded(): void | - | 通知组件重新加载所有数据。 |
+| onDataAdded(index: number):void | number | 通知组件index的位置有数据添加。
index:数据添加位置的索引值 |
+| onDataMoved(from: number, to: number): void | from: number,
to: number | 通知组件数据有移动。
from: 数据移动起始位置,to: 数据移动目标位置。
**说明:**
数据移动前后键值要保持不变,如果键值有变化,应使用删除数据和新增数据接口。 |
+| onDataChanged(index: number): void | number | 通知组件index的位置有数据有变化。
index:数据变化监听器。 |
+| onDataAdd(index: number): void | number | 通知组件index的位置有数据添加。
index:数据添加位置的索引值 |
+| onDataMove(from: number, to: number): void | from: number,
to: number | 通知组件数据有移动。
from: 数据移动起始位置,to: 数据移动目标位置。
**说明:**
数据移动前后键值要保持不变,如果键值有变化,应使用删除数据和新增数据接口。 |
+| onDataChanged(index: number): void | number | 通知组件index的位置有数据有变化。
index:数据变化位置的索引值 |
+
+
+## 使用限制
+
+- LazyForEach必须在容器组件内使用,仅有List、Grid以及Swiper组件支持数据懒加载(即只加载可视部分以及其前后少量数据用于缓冲),其他组件仍然是一次性加载所有的数据。
+
+- LazyForEach在每次迭代中,必须创建且只允许创建一个子组件。
+
+- 生成的子组件必须是允许包含在LazyForEach父容器组件中的子组件。
+
+- 允许LazyForEach包含在if/else条件渲染语句中,也允许LazyForEach中出现if/else条件渲染语句。
+
+- 键值生成器必须针对每个数据生成唯一的值,如果键值相同,将导致键值相同的UI组件被框架忽略,从而无法在父容器内显示。
+
+- LazyForEach必须使用DataChangeListener对象来进行更新,第一个参数dataSource使用状态变量时,状态变量改变不会触发LazyForEach的UI刷新。
+
+- 为了高性能渲染,通过DataChangeListener对象的onDataChange方法来更新UI时,需要生成不同于原来的键值来触发组件刷新。
+
+- itemGenerator函数的调用顺序不一定和数据源中的数据项相同,在开发过程中不要假设itemGenerator和keyGenerator函数是否执行及其执行顺序。例如,以下示例可能无法正常运行:
+
+
+ ```ts
+ LazyForEach(dataSource,
+ item => Text(`${item.i}. item.data.label`),
+ item => item.data.id.toString())
+ ```
+
+
+## 示例
+
+
+```ts
+// Basic implementation of IDataSource to handle data listener
+class BasicDataSource implements IDataSource {
+ private listeners: DataChangeListener[] = [];
+
+ public totalCount(): number {
+ return 0;
+ }
+
+ public getData(index: number): any {
+ return undefined;
+ }
+
+ registerDataChangeListener(listener: DataChangeListener): void {
+ if (this.listeners.indexOf(listener) < 0) {
+ console.info('add listener');
+ this.listeners.push(listener);
+ }
+ }
+
+ unregisterDataChangeListener(listener: DataChangeListener): void {
+ const pos = this.listeners.indexOf(listener);
+ if (pos >= 0) {
+ console.info('remove listener');
+ this.listeners.splice(pos, 1);
+ }
+ }
+
+ notifyDataReload(): void {
+ this.listeners.forEach(listener => {
+ listener.onDataReloaded();
+ })
+ }
+
+ notifyDataAdd(index: number): void {
+ this.listeners.forEach(listener => {
+ listener.onDataAdd(index);
+ })
+ }
+
+ notifyDataChange(index: number): void {
+ this.listeners.forEach(listener => {
+ listener.onDataChange(index);
+ })
+ }
+
+ notifyDataDelete(index: number): void {
+ this.listeners.forEach(listener => {
+ listener.onDataDelete(index);
+ })
+ }
+
+ notifyDataMove(from: number, to: number): void {
+ this.listeners.forEach(listener => {
+ listener.onDataMove(from, to);
+ })
+ }
+}
+
+class MyDataSource extends BasicDataSource {
+ private dataArray: string[] = ['/path/image0', '/path/image1', '/path/image2', '/path/image3'];
+
+ public totalCount(): number {
+ return this.dataArray.length;
+ }
+
+ public getData(index: number): any {
+ return this.dataArray[index];
+ }
+
+ public addData(index: number, data: string): void {
+ this.dataArray.splice(index, 0, data);
+ this.notifyDataAdd(index);
+ }
+
+ public pushData(data: string): void {
+ this.dataArray.push(data);
+ this.notifyDataAdd(this.dataArray.length - 1);
+ }
+}
+
+@Entry
+@Component
+struct MyComponent {
+ private data: MyDataSource = new MyDataSource();
+
+ build() {
+ List({ space: 3 }) {
+ LazyForEach(this.data, (item: string) => {
+ ListItem() {
+ Row() {
+ Image(item).width('30%').height(50)
+ Text(item).fontSize(20).margin({ left: 10 })
+ }.margin({ left: 10, right: 10 })
+ }
+ .onClick(() => {
+ this.data.pushData('/path/image' + this.data.totalCount());
+ })
+ }, item => item)
+ }
+ }
+}
+```
diff --git a/zh-cn/application-dev/quick-start/arkts-rendering-control-overview.md b/zh-cn/application-dev/quick-start/arkts-rendering-control-overview.md
new file mode 100644
index 0000000000000000000000000000000000000000..4ee0e53737ad6000377d5ab1e745ba5a1ca1f4f5
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-rendering-control-overview.md
@@ -0,0 +1,4 @@
+# 渲染控制概述
+
+
+ArkUI通过[自定义组件](arkts-create-custom-components.md)的build()函数和[@builder装饰器](arkts-builder.md)中的声明式UI描述语句构建相应的UI。在声明式描述语句中开发者除了使用系统组件外,还可以使用渲染控制语句来辅助UI的构建,这些渲染控制语句包括控制组件是否显示的条件渲染语句,基于数组数据快速生成组件的循环渲染语句以及针对大数据量场景的数据懒加载语句。
diff --git a/zh-cn/application-dev/quick-start/arkts-rendering-control.md b/zh-cn/application-dev/quick-start/arkts-rendering-control.md
deleted file mode 100644
index 1d1635674d5e913a1a4ac33c84e2a165e092df5d..0000000000000000000000000000000000000000
--- a/zh-cn/application-dev/quick-start/arkts-rendering-control.md
+++ /dev/null
@@ -1,284 +0,0 @@
-# 渲染控制
-
-ArkTS也提供了渲染控制的能力。条件渲染可根据应用的不同状态,渲染对应状态下的UI内容。循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件。
-
-## 条件渲染
-
-使用if/else进行条件渲染。
-
-
-> **说明:**
->
-> - if/else条件语句可以使用状态变量。
->
-> - 使用if/else可以使子组件的渲染依赖条件语句。
->
-> - 必须在容器组件内使用。
->
-> - 某些容器组件限制子组件的类型或数量,将if/else用于这些组件内时,这些限制将同样应用于if/else语句内创建的组件。例如,Grid容器组件的子组件仅支持GridItem组件,在Grid内使用if/else时,则if/else语句内也仅允许使用GridItem组件。
-
-
-```ts
-Column() {
- if (this.count < 0) {
- Text('count is negative').fontSize(14)
- } else if (this.count % 2 === 0) {
- Text('count is even').fontSize(14)
- } else {
- Text('count is odd').fontSize(14)
- }
-}
-```
-
-## 循环渲染
-
-通过循环渲染(ForEach)从数组中获取数据,并为每个数据项创建相应的组件,可减少代码复杂度。
-
-```ts
-ForEach(
- arr: any[],
- itemGenerator: (item: any, index?: number) => void,
- keyGenerator?: (item: any, index?: number) => string
-)
-```
-
-从API version 9开始,该接口支持在ArkTS卡片中使用。
-
-**参数:**
-
-| 参数名 | 参数类型 | 必填 | 参数描述 |
-| ------------- | ------------------------------------- | ---- | ------------------------------------------------------------ |
-| arr | any[] | 是 | 必须是数组,允许设置为空数组,空数组场景下将不会创建子组件。同时允许设置返回值为数组类型的函数,例如arr.slice(1, 3),设置的函数不得改变包括数组本身在内的任何状态变量,如Array.splice、Array.sort或Array.reverse这些改变原数组的函数。 |
-| itemGenerator | (item: any, index?: number) => void | 是 | 生成子组件的lambda函数,为数组中的每一个数据项创建一个或多个子组件,单个子组件或子组件列表必须包括在大括号“{...}”中。 |
-| keyGenerator | (item: any, index?: number) => string | 否 | 匿名函数,用于给数组中的每一个数据项生成唯一且固定的键值。当数据项在数组中的位置更改时,其键值不得更改,当数组中的数据项被新项替换时,被替换项的键值和新项的键值必须不同。键值生成器的功能是可选的,但是,为了使开发框架能够更好地识别数组更改,提高性能,建议提供。如将数组反向时,如果没有提供键值生成器,则ForEach中的所有节点都将重建。 |
-
-> **说明:**
->
-> - ForEach必须在容器组件内使用。
->
-> - 生成的子组件应当是允许包含在ForEach父容器组件中的子组件。
->
-> - 允许子组件生成器函数中包含if/else条件渲染,同时也允许ForEach包含在if/else条件渲染语句中。
->
-> - itemGenerator函数的调用顺序不一定和数组中的数据项相同,在开发过程中不要假设itemGenerator和keyGenerator函数是否执行及其执行顺序。例如,以下示例可能无法正常工作:
->
-> ```ts
-> ForEach(anArray.map((item1, index1) => { return { i: index1 + 1, data: item1 }; }),
-> item => Text(`${item.i}. item.data.label`),
-> item => item.data.id.toString())
-> ```
-
-## 示例
-
-```ts
-// xxx.ets
-@Entry
-@Component
-struct MyComponent {
- @State arr: number[] = [10, 20, 30]
-
- build() {
- Column({ space: 5 }) {
- Button('Reverse Array')
- .onClick(() => {
- this.arr.reverse()
- })
-
- ForEach(this.arr, (item: number) => {
- Text(`item value: ${item}`).fontSize(18)
- Divider().strokeWidth(2)
- }, (item: number) => item.toString())
- }
- }
-}
-```
-
-
-
-## 数据懒加载
-
-通过数据懒加载(LazyForEach)从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。
-
-```ts
-LazyForEach(
- dataSource: IDataSource,
- itemGenerator: (item: any) => void,
- keyGenerator?: (item: any) => string
-): void
-
-interface IDataSource {
- totalCount(): number;
- getData(index: number): any;
- registerDataChangeListener(listener: DataChangeListener): void;
- unregisterDataChangeListener(listener: DataChangeListener): void;
-}
-
-interface DataChangeListener {
- onDataReloaded(): void;
- onDataAdd(index: number): void;
- onDataMove(from: number, to: number): void;
- onDataDelete(index: number): void;
- onDataChange(index: number): void;
-}
-```
-
-**参数:**
-
-| 参数名 | 参数类型 | 必填 | 参数描述 |
-| ------------- | --------------------- | ---- | ------------------------------------------------------------ |
-| dataSource | IDataSource | 是 | 实现IDataSource接口的对象,需要开发者实现相关接口。 |
-| itemGenerator | (item: any, index?: number) => void | 是 | 生成子组件的lambda函数,为数组中的每一个数据项创建一个或多个子组件,单个子组件或子组件列表必须包括在大括号“{...}”中。 |
-| keyGenerator | (item: any, index?: number) => string | 否 | 匿名函数,用于给数组中的每一个数据项生成唯一且固定的键值。当数据项在数组中的位置更改时,其键值不得更改,当数组中的数据项被新项替换时,被替换项的键值和新项的键值必须不同。键值生成器的功能是可选的,但是,为了使开发框架能够更好地识别数组更改,提高性能,建议提供。如将数组反向时,如果没有提供键值生成器,则LazyForEach中的所有节点都将重建。 |
-
-### IDataSource类型说明
-
-| 名称 | 描述 |
-| ------------------------------------------------------------ | ---------------------- |
-| totalCount(): number | 获取数据总数。 |
-| getData(index: number): any | 获取索引值index对应的数据。 |
-| registerDataChangeListener(listener:DataChangeListener): void | 注册数据改变的监听器。 |
-| unregisterDataChangeListener(listener:DataChangeListener): void | 注销数据改变的监听器。 |
-
-### DataChangeListener类型说明
-
-| 名称 | 描述 |
-| -------------------------------------------------------- | -------------------------------------- |
-| onDataReloaded(): void | 重新加载所有数据。 |
-| onDataAdded(index: number): voiddeprecated | 通知组件index的位置有数据添加。从API Version 8开始废弃,建议使用onDataAdd。 |
-| onDataMoved(from: number, to: number): voiddeprecated | 通知组件数据从from的位置移到to的位置。从API Version 8开始废弃,建议使用onDataMove。 |
-| onDataDeleted(index: number): voiddeprecated | 通知组件index的位置有数据删除。从API Version 8开始废弃,建议使用onDataDelete。 |
-| onDataChanged(index: number): voiddeprecated | 通知组件index的位置有数据变化。 从API Version 8开始废弃,建议使用onDataChange。 |
-| onDataAdd(index: number): void8+ | 通知组件index的位置有数据添加。 |
-| onDataMove(from: number, to: number): void8+ | 通知组件数据从from的位置移到to的位置。 |
-| onDataDelete(index: number): void8+ | 通知组件index的位置有数据删除。 |
-| onDataChange(index: number): void8+ | 通知组件index的位置有数据变化。 |
-
-## 示例
-
-```ts
-// xxx.ets
-class BasicDataSource implements IDataSource {
- private listeners: DataChangeListener[] = []
-
- public totalCount(): number {
- return 0
- }
-
- public getData(index: number): any {
- return undefined
- }
-
- registerDataChangeListener(listener: DataChangeListener): void {
- if (this.listeners.indexOf(listener) < 0) {
- console.info('add listener')
- this.listeners.push(listener)
- }
- }
-
- unregisterDataChangeListener(listener: DataChangeListener): void {
- const pos = this.listeners.indexOf(listener);
- if (pos >= 0) {
- console.info('remove listener')
- this.listeners.splice(pos, 1)
- }
- }
-
- notifyDataReload(): void {
- this.listeners.forEach(listener => {
- listener.onDataReloaded()
- })
- }
-
- notifyDataAdd(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataAdd(index)
- })
- }
-
- notifyDataChange(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataChange(index)
- })
- }
-
- notifyDataDelete(index: number): void {
- this.listeners.forEach(listener => {
- listener.onDataDelete(index)
- })
- }
-
- notifyDataMove(from: number, to: number): void {
- this.listeners.forEach(listener => {
- listener.onDataMove(from, to)
- })
- }
-}
-
-class MyDataSource extends BasicDataSource {
- // 初始化数据列表
- private dataArray: string[] = ['/path/image0.png', '/path/image1.png', '/path/image2.png', '/path/image3.png']
-
- public totalCount(): number {
- return this.dataArray.length
- }
-
- public getData(index: number): any {
- return this.dataArray[index]
- }
-
- public addData(index: number, data: string): void {
- this.dataArray.splice(index, 0, data)
- this.notifyDataAdd(index)
- }
-
- public pushData(data: string): void {
- this.dataArray.push(data)
- this.notifyDataAdd(this.dataArray.length - 1)
- }
-}
-
-@Entry
-@Component
-struct MyComponent {
- private data: MyDataSource = new MyDataSource()
-
- build() {
- List({ space: 3 }) {
- LazyForEach(this.data, (item: string) => {
- ListItem() {
- Row() {
- Image(item).width(50).height(50)
- Text(item).fontSize(20).margin({ left: 10 })
- }.margin({ left: 10, right: 10 })
- }
- .onClick(() => {
- // 每点击一次列表项,数据增加一项
- this.data.pushData('/path/image' + this.data.totalCount() + '.png')
- })
- }, item => item)
- }.height('100%').width('100%')
- }
-}
-```
-
-> **说明:**
->
-> - LazyForEach必须在容器组件内使用,目前仅有List、Grid以及Swiper组件支持数据懒加载(即只加载可视部分以及其前后少量数据用于缓冲),其他组件仍然是一次性加载所有的数据。
->
-> - LazyForEach在每次迭代中,必须创建且只允许创建一个子组件。
->
-> - 生成的子组件必须是允许包含在LazyForEach父容器组件中的子组件。
->
-> - 允许LazyForEach包含在if/else条件渲染语句中。
->
-> - 为了高性能渲染,通过DataChangeListener对象的onDataChange方法来更新UI时,仅当itemGenerator中创建的子组件内使用了状态变量时,才会触发组件刷新。
->
-> - itemGenerator函数的调用顺序不一定和数据源中的数据项相同,在开发过程中不要假设itemGenerator和keyGenerator函数是否执行及其执行顺序。例如,以下示例可能无法正常工作:
->
-> ```ts
-> LazyForEach(dataSource,
-> item => Text(`${item.i}. item.data.label`),
-> item => item.data.id.toString())
-> ```
-
-
\ No newline at end of file
diff --git a/zh-cn/application-dev/quick-start/arkts-restrictions-and-extensions.md b/zh-cn/application-dev/quick-start/arkts-restrictions-and-extensions.md
deleted file mode 100644
index c0ce64bfe9264ecab6379a62dacb3a94409646f0..0000000000000000000000000000000000000000
--- a/zh-cn/application-dev/quick-start/arkts-restrictions-and-extensions.md
+++ /dev/null
@@ -1,257 +0,0 @@
-# 使用限制与扩展
-
-## 在生成器函数中的使用限制
-
-ArkTS语言的使用在生成器函数中存在一定的限制:
-
-- 表达式仅允许在字符串(${expression})、if/else条件语句、ForEach的参数以及组件的参数中使用。
-
-- 任何表达式都不能导致应用程序中状态变量(@State、@Link、@Prop)的改变,否则会造成未定义和潜在不稳定的框架行为。
-
-- 生成器函数内部不能有局部变量。
-
-上述限制都不适用于事件方法(如onClick)的匿名函数实现。
-
-## 变量的双向绑定
-
-ArkTS支持通过$$双向绑定变量,通常应用于状态值频繁改变的变量。
-
-- 当前$$支持基础类型变量,以及@State、@Link和@Prop装饰的变量。
-- 当前$$仅支持[bindPopup](../reference/arkui-ts/ts-universal-attributes-popup.md)属性方法的show参数,[Radio](../reference/arkui-ts/ts-basic-components-radio.md)组件的checked属性,[Refresh](../reference/arkui-ts/ts-container-refresh.md)组件的refreshing参数。
-- $$绑定的变量变化时,仅渲染刷新当前组件,提高渲染速度。
-
-```ts
-// xxx.ets
-@Entry
-@Component
-struct bindPopupPage {
- @State customPopup: boolean = false
-
- build() {
- Column() {
- Button('Popup')
- .margin(20)
- .onClick(() => {
- this.customPopup = !this.customPopup
- })
- .bindPopup($$this.customPopup, {
- message: "showPopup"
- })
- }
- }
-}
-```
-
-
-
-## 状态变量数据类型声明使用限制
-
-1. 所有的状态装饰器变量需要显式声明变量类型,不允许声明any,不支持Date数据类型。
-
- 示例:
-
- ```ts
- // xxx.ets
- @Entry
- @Component
- struct DatePickerExample {
- //错误写法: @State isLunar: any = false
- @State isLunar: boolean = false
- //错误写法: @State selectedDate: Date = new Date('2021-08-08')
- private selectedDate: Date = new Date('2021-08-08')
-
- build() {
- Column() {
- Button('切换公历农历')
- .margin({ top: 30 })
- .onClick(() => {
- this.isLunar = !this.isLunar
- })
- DatePicker({
- start: new Date('1970-1-1'),
- end: new Date('2100-1-1'),
- selected: this.selectedDate
- })
- .lunar(this.isLunar)
- .onChange((value: DatePickerResult) => {
- this.selectedDate.setFullYear(value.year, value.month, value.day)
- console.info('select current date is: ' + JSON.stringify(value))
- })
-
- }.width('100%')
- }
- }
- ```
-
- 
-
-2. @State、@Provide、 @Link和@Consume四种状态变量的数据类型声明只能由简单数据类型或引用数据类型的其中一种构成。
-
- 类型定义中的Length、ResourceStr、ResourceColor三个类型是简单数据类型或引用数据类型的组合,所以不能被以上四种状态装饰器变量使用。
- Length、ResourceStr、ResourceColor的定义请看文档[arkui-ts类型定义](../../application-dev/reference/arkui-ts/ts-types.md)。
-
- 示例:
-
- ```ts
- // xxx.ets
- @Entry
- @Component
- struct IndexPage {
- //错误写法: @State message: string | Resource = 'Hello World'
- @State message: string = 'Hello World'
- //错误写法: @State message: ResourceStr = $r('app.string.hello')
- @State resourceStr: Resource = $r('app.string.hello')
-
- build() {
- Row() {
- Column() {
- Text(`${this.message}`)
- .fontSize(50)
- .fontWeight(FontWeight.Bold)
- }
- .width('100%')
- }
- .height('100%')
- }
- }
- ```
-
- 
-
-## 自定义组件成员变量初始化的方式与约束
-
-组件的成员变量可以通过两种方式初始化:
-
-- 本地初始化:
-
- ```ts
- @State counter: Counter = new Counter()
- ```
-- 在构造组件时通过构造参数初始化:
-
- ```ts
- MyComponent({counter: $myCounter})
- ```
-
-具体允许哪种方式取决于状态变量的装饰器:
-
-| 装饰器类型 | 本地初始化 | 通过构造函数参数初始化 |
-| ----------------- | ----- | ----------- |
-| @State | 必须 | 可选 |
-| @Prop | 禁止 | 必须 |
-| @Link | 禁止 | 必须 |
-| @StorageLink | 必须 | 禁止 |
-| @StorageProp | 必须 | 禁止 |
-| @LocalStorageLink | 必须 | 禁止 |
-| @LocalStorageProp | 必须 | 禁止 |
-| @Provide | 必须 | 可选 |
-| @Consume | 禁止 | 禁止 |
-| @ObjectLink | 禁止 | 必须 |
-| 常规成员变量 | 推荐 | 可选 |
-
-从上表中可以看出:
-
-- @State变量需要本地初始化,初始化的值可以被构造参数覆盖。
-
-- @Prop和@Link变量必须且仅通过构造函数参数进行初始化。
-
-通过构造函数方法初始化成员变量,需要遵循如下规则:
-
-| **从父组件中的变量(右)到子组件中的变量(下)** | **regular** | **@State** | **@Link** | **@Prop** | **@Provide** | **@Consume** | **@ObjectLink** |
-| -------------------------- | ----------- | ---------- | --------- | --------- | ------------ | ------------ | --------------- |
-| **regular** | 支持 | 支持 | 支持 | 支持 | 不支持 | 不支持 | 支持 |
-| **@State** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
-| **@Link** | 不支持 | 支持(1) | 支持(1) | 支持(1) | 支持(1) | 支持(1) | 支持(1) |
-| **@Prop** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
-| **@Provide** | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 | 支持 |
-| **@Consume** | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 |
-| **@ObjectLink** | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 | 不支持 |
-
-| **从父组件中的变量(右)到子组件中的变量(下)** | **@StorageLink** | **@StorageProp** | **@LocalStorageLink** | **@LocalStorageProp** |
-| -------------------------- | ---------------- | ---------------- | --------------------- | --------------------- |
-| **regular** | 支持 | 不支持 | 不支持 | 不支持 |
-| **@State** | 支持 | 支持 | 支持 | 支持 |
-| **@Link** | 支持(1) | 支持(1) | 支持(1) | 支持(1) |
-| **@Prop** | 支持 | 支持 | 支持 | 支持 |
-| **@Provide** | 支持 | 支持 | 支持 | 支持 |
-| **@Consume** | 不支持 | 不支持 | 不支持 | 不支持 |
-| **@ObjectLink** | 不支持 | 不支持 | 不支持 | 不支持 |
-
-> **说明**
->
-> **支持(1)**:必须使用`$`, 例如 `this.$varA`。
-> **regular**:未加修饰的常规变量。
-
-从上表中可以看出:
-
-- 子组件的@ObjectLink变量不支持父组件装饰器变量的直接赋值,其父组件的源必须是数组的项或对象的属性,该数组或对象必现用`@State`、`@Link`、`@Provide`、`@Consume`或`@ObjectLink`装饰器修饰。
-
-- 父组件的常规变量可以用于初始化子组件的`@State`变量,但不能用于初始化`@Link`、`@Consume`和`@ObjectLink`变量。
-
-- 父组件的@State变量可以初始化子组件的`@Prop`、`@Link`(通过$)或常规变量,但不能初始化子组件的@Consume变量。
-
-- 父组件的@Link变量不可以初始化子组件的`@Consume`和`@ObjectLink`变量。
-
-- 父组件的@Prop变量不可以初始化子组件的`@Consume`和`@ObjectLink`变量。
-
-- 不允许从父组件初始化`@StorageLink`, `@StorageProp`, `@LocalStorageLink`, `@LocalStorageProp`修饰的变量。
-
-- 除了上述规则外,还需要遵循TS的强类型规则。
-
-示例:
-```ts
-@Entry
-@Component
-struct Parent {
- message: string = "Hello World"
- build() {
- Column() {
- Child({
- stateMessage: this.message,
- /* ArkTS:ERROR The regular property 'message' cannot be assigned
- to the @Link property 'linkMessage'.*/
- linkMessage: this.$message
- })
- }
- .width('100%')
- }
-}
-
-@Component
-struct Child {
- @State stateMessage: string = "Hello World"
- @Link linkMessage: string
- build() {
- Column() {
- Text(this.stateMessage)
- .fontSize(50)
- .fontWeight(FontWeight.Bold)
- }
- .width('100%')
- }
-}
-```
-
-## 自定义组件名,类名,函数名和系统组件名相同约束。
-
-自定义组件名,类名,函数名不能和系统组件名相同。
-
-示例:
-
-```
-// Rect.ets
-export class Rect {
- constructor(){}
-}
-// Index.ets
-// ERROR: The module name 'Rect' can not be the same as the inner component name.
-import { Rect } from './Rect';
-@Entry
-@Component
-struct Index {
- build() {
-
- }
-}
-```
-
diff --git a/zh-cn/application-dev/quick-start/arkts-state-management-overview.md b/zh-cn/application-dev/quick-start/arkts-state-management-overview.md
new file mode 100644
index 0000000000000000000000000000000000000000..f9cef2129955f17534cb1efd1be00c17cad7b120
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-state-management-overview.md
@@ -0,0 +1,125 @@
+# 状态管理概述
+
+
+在前文的描述中,我们构建的页面多为静态界面。如果希望构建一个动态的、有交互的界面,就需要引入“状态”的概念。
+
+
+ **图1** 效果图
+
+
+
+
+上面的示例中,用户与应用程序的交互触发了文本状态变更,状态变更引起了UI渲染,UI从“Hello World”变更为“Hello ArkUI”。
+
+
+在声明式UI编程框架中,UI是程序状态的运行结果,用户构建了一个UI模型,其中应用的运行时的状态是参数。当参数改变时,UI作为返回结果,也将进行对应的改变。这些运行时的状态变化所带来的UI的重新渲染,在ArkUI中统称为状态管理机制。
+
+
+自定义组件拥有变量,变量必须被装饰器装饰才可以成为状态变量,状态变量的改变会引起UI的渲染刷新。如果不使用状态变量,UI只能在初始化时渲染,后续将不会再刷新。 下图展示了State和View(UI)之间的关系。
+
+
+
+
+
+- View(UI):UI渲染,一般指自定义组件的build方法和\@Builder装饰的方法内的UI描述。
+
+- State:状态,一般指的是装饰器装饰的数据。用户通过触发组件的事件方法,改变状态数据。状态数据的改变,引起UI的重新渲染。
+
+
+## 基本概念
+
+- 状态变量:被状态装饰器装饰的变量,改变会引起UI的渲染更新。
+
+- 常规变量:没有状态的变量,通常应用于辅助计算。它的改变永远不会引起UI的刷新。
+
+- 数据源/同步源:状态变量的原始来源,可以同步给不同的状态数据。通常意义为父组件传给子组件的数据。
+
+- 命名参数机制:父组件通过指定参数传递给子组件的状态变量,为父子传递同步参数的主要手段。示例:CompA: ({ aProp: this.aProp })。
+
+- 从父组件初始化:父组件传使用命名参数机制,将指定参数传递给子组件。本地初始化的默认值在有父组件传值的情况下,会被覆盖。示例:
+
+ ```ts
+ @Component
+ struct MyComponent {
+ @State count: number = 0;
+ private increaseBy: number = 1;
+
+ build() {
+ }
+ }
+
+ @Component
+ struct Parent {
+ build() {
+ Column() {
+ // 从父组件初始化,覆盖本地定义的默认值
+ MyComponent({ count: 1, increaseBy: 2 })
+ }
+ }
+ }
+ ```
+
+- 初始化子节点:组件中状态变量可以传递给子组件,初始化子组件对应的状态变量。示例同上。
+
+- 本地初始化:变量声明的时候赋值,作为初始化的默认值。示例:\@State count: number = 0。
+
+
+## 装饰器总览
+
+ArkUI提供了多种装饰器,通过使用这些装饰器,状态变量不仅可以观察在组件内的改变,还可以在不同组件层级间传递,比如父子组件、跨组件层级,也可以观察全局范围内的变化。根据状态变量的影响范围,将所有的装饰器可以大致分为:
+
+
+- 管理组件拥有状态的装饰器:组件级别的状态管理,可以观察组件内变化,和不同组件层级的变化,但需要唯一观察同一个组件树上,即同一个页面内。
+
+- 管理应用拥有状态的装饰器:应用级别的状态管理,可以观察不同页面,甚至不同UIAbility的状态变化,是应用内全局的状态管理。
+
+
+从数据的传递形式和同步类型层面看,装饰器也可分为:
+
+
+- 只读的单向传递;
+
+- 可变更的双向传递。
+
+
+图示如下,具体装饰器的介绍,可详见[管理组件拥有的状态](arkts-state.md)和[管理应用拥有的状态](arkts-application-state-management-overview.md)。开发者可以灵活地利用这些能力来实现数据和UI的联动。
+
+
+
+
+
+上图中,Components部分的装饰器为组件级别的状态管理,Application部分为应用的状态管理。开发者可以通过\@StorageLink/\@LocalStorageLink和\@StorageProp/\@LocalStorageProp实现应用和组件状态的双向和单向同步。图中箭头方向为数据同步方向,单箭头为单向同步,双箭头为双向同步。
+
+
+[管理组件拥有的状态](arkts-state.md),即图中Components级别的状态管理:
+
+
+- \@State:\@State装饰的变量拥有其所属组件的状态,可以作为其子组件单向和双向同步的数据源。当其数值改变时,会引起相关组件的渲染刷新。
+
+- \@Prop:\@Prop装饰的变量可以和父组件建立单向同步关系,\@Prop装饰的变量是可变的,但修改不会同步回父组件。
+
+- \@Link:\@Link装饰的变量和父组件构建双向同步关系的状态变量,父组件会接受来自\@Link装饰的变量的修改的同步,父组件的更新也会同步给\@Link装饰的变量。
+
+- \@Provide/\@Consume:\@Provide/\@Consume装饰的变量用于跨组件层级(多层组件)同步状态变量,可以不需要通过参数命名机制传递,通过alias(别名)或者属性名绑定。
+
+- \@Observed:\@Observed装饰class,需要观察多层嵌套场景的class需要被\@Observed装饰。单独使用\@Observed没有任何作用,需要和\@ObjectLink、\@Prop连用。
+
+- \@ObjectLink:\@ObjectLink装饰的变量接收\@Observed装饰的class的实例,应用于观察多层嵌套场景,和父组件的数据源构建双向同步。
+
+
+[管理应用拥有的状态](arkts-application-state-management-overview.md),即图中Application级别的状态管理:
+
+
+- AppStorage是应用程序中的一个特殊的单例LocalStorage对象,是应用级的数据库,和进程绑定,通过[@StorageProp](arkts-appstorage.md#storageprop)和[@StorageLink](arkts-appstorage.md#storagelink)装饰器可以和组件联动。
+
+- AppStorage是应用状态的“中枢”,需要和组件(UI)交互的数据存入AppStorage,比如持久化数据PersistentStorage和环境变量Environment。UI再通过AppStorage提供的装饰器或者API接口,访问这些数据;
+
+- 框架还提供了LocalStorage,AppStorage是LocalStorage特殊的单例。LocalStorage是应用程序声明的应用状态的内存“数据库”,通常用于页面级的状态共享,通过[@LocalStorageProp](arkts-localstorage.md#localstorageprop)和[@LocalStorageLink](arkts-localstorage.md#localstoragelink)装饰器可以和UI联动。
+
+
+### 其他状态管理功能
+
+\@Watch用于监听状态变量的变化。
+
+
+$$运算符:给内置组件提供TS变量的引用,使得TS变量和内置组件的内部状态保持同步。
diff --git a/zh-cn/application-dev/quick-start/arkts-state-mgmt-application-level.md b/zh-cn/application-dev/quick-start/arkts-state-mgmt-application-level.md
deleted file mode 100644
index 7e8c55efd865f4d4689be94fb4be6aecfb50717b..0000000000000000000000000000000000000000
--- a/zh-cn/application-dev/quick-start/arkts-state-mgmt-application-level.md
+++ /dev/null
@@ -1,270 +0,0 @@
-# 应用级变量的状态管理
-
-在前面的章节中,已经讲述了如何管理页面级变量的状态,本章将说明如何管理应用级变量的状态,具体接口说明请参考[应用级变量的状态管理接口](../reference/arkui-ts/ts-state-management.md)。
-
-## AppStorage
-
-[AppStorage](../reference/arkui-ts/ts-state-management.md#appstorage)是应用程序中的单例对象,由UI框架在应用程序启动时创建,在应用程序退出时销毁,为应用程序范围内的可变状态属性提供中央存储。
-
-AppStorage包含整个应用程序中需要访问的所有状态属性,只要应用程序保持运行,AppStorage就会保存所有属性及属性值,属性值可以通过唯一的键值进行访问。
-
-组件可以通过装饰器将应用程序状态数据与AppStorage进行同步,应用业务逻辑的实现也可以通过接口访问AppStorage。
-
-AppStorage的选择状态属性可以与不同的数据源或数据接收器同步,这些数据源和接收器可以是设备上的本地或远程,并具有不同的功能,如数据持久性。这样的数据源和接收器可以独立于UI在业务逻辑中实现。
-
-默认情况下,AppStorage中的属性是可变的,AppStorage还可使用不可变(只读)属性。
-
-> **说明**:[Worker](../reference/apis/js-apis-worker.md)和主线程只能通过[postMessage](../reference/apis/js-apis-worker.md#postmessage)交互,不能使用AppStorage进行交互。
-
-### @StorageLink装饰器
-
-组件通过使用@StorageLink(key)装饰的状态变量,与AppStorage建立双向数据绑定,key为AppStorage中的属性键值。当创建包含@StorageLink的状态变量的组件时,该状态变量的值将使用AppStorage中的值进行初始化。在UI组件中对@StorageLink的状态变量所做的更改将同步到AppStorage,并从AppStorage同步到任何其他绑定实例中,如PersistentStorage或其他绑定的UI组件。
-
-### @StorageProp装饰器
-
-组件通过使用@StorageProp(key)装饰的状态变量,与AppStorage建立单向数据绑定,key标识AppStorage中的属性键值。当创建包含@StorageProp的状态变量的组件时,该状态变量的值将使用AppStorage中的值进行初始化。AppStorage中属性值的更改会导致绑定该状态变量的UI组件进行状态更新。
-
-### 示例
-
-每次用户单击Count按钮时,this.varA变量值都会增加1,此变量与AppStorage中的varA同步。每次用户单击language按钮时,修改AppStorage中的languageCode,此修改会同步给this.languageCode变量。
-
-```ts
-// xxx.ets
-@Entry
-@Component
-struct ComponentA {
- @StorageLink('varA') varA: number = 2
- @StorageProp('languageCode') languageCode: string = 'en'
- private label: string = 'count'
-
- aboutToAppear() {
- this.label = (this.languageCode === 'zh') ? '数量' : 'Count'
- }
-
- build() {
- Column() {
- Row({ space: 20 }) {
- Button(`${this.label}: ${this.varA}`)
- .onClick(() => {
- AppStorage.Set('varA', AppStorage.Get('varA') + 1)
- })
- Button(`language: ${this.languageCode}`)
- .onClick(() => {
- if (AppStorage.Get('languageCode') === 'zh') {
- AppStorage.Set('languageCode', 'en')
- } else {
- AppStorage.Set('languageCode', 'zh')
- }
- this.label = (this.languageCode === 'zh') ? '数量' : 'Count'
- })
- }
- .margin({ top: 50, bottom: 50 })
-
- Row() {
- Button(`更改@StorageLink修饰的变量:${this.varA}`).height(40).fontSize(14)
- .onClick(() => {
- this.varA++
- })
- }
- }.width('100%')
- }
-}
-```
-
-
-
-## LocalStorage
-
-> **说明:**
->
-> 该接口从API version 9开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。
-
-LocalStorage是应用程序中的存储单元,生命周期跟随其关联的Ability。在Stage模型下,LocalStorage解决AppStorage共享范围过大的问题,提供Ability之间全局数据的隔离。同时,LocalStorage为应用程序范围内的可变状态属性和非可变状态属性提供存储,可变状态属性和非可变状态属性是构建应用程序UI的一部分,如一个Ability的UI。解决App与Ability之间数据互相干扰问题,多实例场景下同一个Ability类的不同Ability实例之间的数据互相干扰问题。在分布式迁移的场景下,Ability是系统调度的最小单元,配合LocalStorage更方便实现组件的数据迁移。
-
-应用层:一个应用程序可以创建多个LocalStorage实例,应用程序的每一个Ability对应一个LocalStorage实例。
-
-Ability:一个应用程序可以拥有多个Ability,一个Ability中的所有子组件最多可以分配一个LocalStorage实例。并且,Ability中的所有子组件都将继承对此LocalStorage实例存储对象的访问权。
-
-一个组件最多可以访问一个LocalStorage实例,一个LocalStorage对象可以分配给多个组件。
-
-### @LocalStorageLink装饰器
-
-组件通过使用@LocalStorageLink(key)装饰的状态变量,key值为LocalStorage中的属性键值,与LocalStorage建立双向数据绑定。当创建包含@LocalStorageLink的状态变量的组件时,该状态变量的值将会使用LocalStorage中的值进行初始化。如果LocalStorage中未定义初始值,将使用@LocalStorageLink定义的初始值。在UI组件中对@LocalStorageLink的状态变量所做的更改将同步到LocalStorage中,并从LocalStorage同步到Ability下的组件中。
-
-### @LocalStorageProp装饰器
-
-组件通过使用LocalStorageProp(key)装饰的状态变量,key值为LocalStorage中的属性键值,与LocalStorage建立单向数据绑定。当创建包含@LocalStorageProp的状态变量的组件时,该状态变量的值将使用LocalStorage中的值进行初始化。LocalStorage中的属性值的更改会导致当前Ability下的所有UI组件进行状态更新。
-
-> **说明:** 创建LocalStorage实例时如未定义初始值,可以使用组件内@LocalStorageLink和@LocalStorageProp的初始值。如果定义时给定了初始值,那么不会再使用@LocalStorageLink和@LocalStorageProp的初始值。
-
-### 示例1(在一个Ability中创建LocalStorage)
-
-LocalStorage通过loadContent接口加载,接口说明详见[loadContent](../reference/apis/js-apis-window.md#loadcontent9-1)。
-
-```ts
-// MainAbility.ts
-import Ability from '@ohos.application.Ability'
-
-export default class MainAbility extends Ability {
- storage: LocalStorage
-
- onCreate() {
- this.storage = new LocalStorage()
- this.storage.setOrCreate('storageSimpleProp', 121)
- console.info('[Demo MainAbility onCreate]')
- }
-
- onDestroy() {
- console.info('[Demo MainAbility onDestroy]')
- }
-
- onWindowStageCreate(windowStage) {
- // storage作为参数传递给loadContent接口
- windowStage.loadContent('pages/Index', this.storage)
- }
-
- onWindowStageDestroy() {
- console.info('[Demo] MainAbility onWindowStageDestroy')
- }
-
- onForeground() {
- console.info('[Demo] MainAbility onForeground')
- }
-
- onBackground() {
- console.info('[Demo] MainAbility onBackground')
- }
-}
-```
-
-@Component组件获取数据
-
-```ts
-// Index.ets
-let storage = LocalStorage.GetShared()
-
-@Entry(storage)
-@Component
-struct LocalStorageComponent {
- @LocalStorageLink('storageSimpleProp') simpleVarName: number = 0
-
- build() {
- Column() {
- Button(`LocalStorageLink: ${this.simpleVarName.toString()}`)
- .margin(20)
- .onClick(() => {
- this.simpleVarName += 1
- })
- Text(JSON.stringify(this.simpleVarName))
- .fontSize(50)
- LocalStorageComponentProp()
- }.width('100%')
- }
-}
-
-@Component
-struct LocalStorageComponentProp {
- @LocalStorageProp('storageSimpleProp') simpleVarName: number = 0
-
- build() {
- Column() {
- Button(`LocalStorageProp: ${this.simpleVarName.toString()}`)
- .margin(20)
- .onClick(() => {
- this.simpleVarName += 1
- })
- Text(JSON.stringify(this.simpleVarName))
- .fontSize(50)
- }.width('100%')
- }
-}
-```
-
-
-
-### 示例2(在Entry页面定义LocalStorage)
-
-```ts
-// xxx.ets
-let storage = new LocalStorage({ "PropA": 47 })
-
-@Entry(storage)
-@Component
-struct ComA {
- @LocalStorageLink("PropA") storageLink: number = 1
-
- build() {
- Column() {
- Text(`Parent from LocalStorage ${this.storageLink}`)
- .fontSize(18)
- .margin(20)
- .onClick(() => this.storageLink += 1)
- Child()
- }
- }
-}
-
-@Component
-struct Child {
- @LocalStorageLink("PropA") storageLink: number = 1
-
- build() {
- Text(`Child from LocalStorage ${this.storageLink}`)
- .fontSize(18)
- .margin(20)
- .onClick(() => this.storageLink += 1)
- }
-}
-```
-
-
-
-## PersistentStorage
-
-[PersistentStorage](../reference/arkui-ts/ts-state-management.md#persistentstorage)提供了一些静态方法用来管理应用持久化数据,可以将特定标记的持久化数据链接到AppStorage中,并由AppStorage接口访问对应持久化数据,或者通过@StorageLink装饰器来访问对应key的变量。
-
-> **说明:**
->
-> - PersistentStorage的PersistProp接口使用时,需要保证输入对应的key在AppStorage中存在。
-> - PersistentStorage的DeleteProp接口使用时,只能对本次应用启动时已经link过的数据生效。
-
-```ts
-// xxx.ets
-PersistentStorage.PersistProp('highScore', '0')
-
-@Entry
-@Component
-struct PersistentComponent {
- @StorageLink('highScore') highScore: string = '0'
- @State currentScore: number = 0
-
- build() {
- Column() {
- if (this.currentScore === Number(this.highScore)) {
- Text(`new highScore : ${this.highScore}`).fontSize(18)
- }
- Button(`goal!, currentScore : ${this.currentScore}`)
- .margin(20)
- .onClick(() => {
- this.currentScore++
- if (this.currentScore > Number(this.highScore)) {
- this.highScore = this.currentScore.toString()
- }
- })
- }.width('100%')
- }
-}
-```
-
-
-
-## Environment
-
-[Environment](../reference/arkui-ts/ts-state-management.md#environment)是框架在应用程序启动时创建的单例对象,它为AppStorage提供了一系列应用程序需要的环境状态数据,这些数据描述了应用程序运行的设备环境,包括系统语言、深浅色模式等等。Environment及其属性是不可变的,所有数据类型均为简单类型。如下示例展示了从Environment获取系统是否开启无障碍屏幕朗读:
-
-```ts
-Environment.EnvProp('accessibilityEnabled', 'default')
-var enable = AppStorage.Get('accessibilityEnabled')
-```
-
-accessibilityEnabled是Environment提供的系统默认变量识别符。首先需要将对应系统属性绑定到AppStorage上,再通过AppStorage中的方法或者装饰器访问对应的系统属性数据。
\ No newline at end of file
diff --git a/zh-cn/application-dev/quick-start/arkts-state-mgmt-concepts.md b/zh-cn/application-dev/quick-start/arkts-state-mgmt-concepts.md
deleted file mode 100644
index 1e446d1ebd7dc34fbfacf8917bfbfb88cc1384d7..0000000000000000000000000000000000000000
--- a/zh-cn/application-dev/quick-start/arkts-state-mgmt-concepts.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# 基本概念
-
-ArkTS提供了多维度的状态管理机制,在ArkUI开发框架中,和UI相关联的数据,不仅可以在组件内使用,还可以在不同组件层级间传递,比如父子组件之间、爷孙组件之间,也可以是应用全局范围内的传递。另外,从数据的传递形式来看,可分为只读的单向传递和可变更的双向传递。开发者可以灵活地利用这些能力来实现数据和UI的联动。
-
-
-
-
-
-## 页面级变量的状态管理
-
-| 装饰器 | 装饰内容 | 说明 |
-| ----------- | ------------------------- | ------------------------------------------------------------ |
-| @State | 基本数据类型,类,数组 | 修饰的状态数据被修改时会触发组件的build方法进行UI界面更新。 |
-| @Prop | 基本数据类型 | 修改后的状态数据用于在父组件和子组件之间建立单向数据依赖关系。修改父组件关联数据时,当前组件会重新渲染。 |
-| @Link | 基本数据类型,类,数组 | 父子组件之间的双向数据绑定,父组件的内部状态数据作为数据源,任何一方所做的修改都会反映给另一方。 |
-| @Observed | 类 | @Observed应用于类,表示该类中的数据变更被UI页面管理。 |
-| @ObjectLink | 被@Observed所装饰类的对象 | @ObjectLink装饰的状态数据被修改时,在父组件或者其他兄弟组件内与它关联的状态数据所在的组件都会重新渲染。 |
-| @Provide | 基本数据类型,类,数组 | @Provide作为数据的提供方,可以更新其子孙节点的数据,并触发页面重新渲染。 |
-| @Consume | 基本数据类型,类,数组 | @Consume装饰的变量在感知到@Provide装饰的变量更新后,会触发当前自定义组件的重新渲染。 |
-
-## 应用级变量的状态管理
-
-AppStorage是整个应用程序状态的中心“数据库”,UI框架会针对应用程序创建单例AppStorage对象,并提供相应的装饰器和接口供应用程序使用。
-
-- @StorageLink:@StorageLink(name)的原理类似于@Consume(name),不同的是,该给定名称的链接对象是从AppStorage中获得的,在UI组件和AppStorage之间建立双向绑定同步数据。
-- @StorageProp:@StorageProp(name)将UI组件数据与AppStorage进行单向同步,AppStorage中值的更改会更新UI组件中的数据,但UI组件无法更改AppStorage中的数据。
-- AppStorage还提供了用于业务逻辑实现的API,用于添加、读取、修改和删除应用程序的状态数据,此API所做的更改会导致修改的状态数据同步到UI组件上进行UI更新。
-- LocalStorage是应用程序中每一个Ability的存储器。
-- @LocalStorageLink:组件通过使用@LocalStorageLink(key)装饰的状态变量,key值为LocalStorage中的属性键值,与LocalStorage建立双向数据绑定。
-- @LocalStorageProp:组件通过使用@LocalStorageProp(key)装饰的状态变量,key值为LocalStorage中的属性键值,与LocalStorage建立单向数据绑定。
-- PersistentStorage提供了一些静态方法用来管理应用持久化数据,可以将特定标记的持久化数据链接到AppStorage中,并由AppStorage接口访问对应持久化数据,或者通过@StorageLink装饰器来访问对应key的变量。
-- Environment是框架在应用程序启动时创建的单例对象,它为AppStorage提供了一系列应用程序需要的环境状态数据,这些数据描述了应用程序运行的设备环境。
-
-请参考[状态变量数据类型声明的使用限制](arkts-restrictions-and-extensions.md)了解状态变量使用规范。
diff --git a/zh-cn/application-dev/quick-start/arkts-state-mgmt-page-level.md b/zh-cn/application-dev/quick-start/arkts-state-mgmt-page-level.md
deleted file mode 100644
index 5691c58542787a93566ff2feda118fd608f5eda2..0000000000000000000000000000000000000000
--- a/zh-cn/application-dev/quick-start/arkts-state-mgmt-page-level.md
+++ /dev/null
@@ -1,521 +0,0 @@
-# 页面级变量的状态管理
-
-@State、@Prop、@Link、@Provide、@Consume、@ObjectLink、@Observed和@Watch用于管理页面级变量的状态。
-
-请参考[状态变量多种数据类型声明的使用限制](./arkts-restrictions-and-extensions.md)了解@State、@Provide、 @Link和@Consume四种状态变量的约束条件。
-
-## @State
-
-@State装饰的变量是组件内部的状态数据,当这些状态数据被修改时,将会调用所在组件的build方法进行UI刷新。
-
-@State状态数据具有以下特征:
-
-- 支持多种类型数据:支持class、number、boolean、string强类型数据的值类型和引用类型,以及这些强类型构成的数组,即Array<class>、Array<string>、Array<boolean>、Array<number>。不支持object和any。
-- 支持多实例:组件不同实例的内部状态数据独立。
-- 内部私有:标记为@State的属性是私有变量,只能在组件内访问。
-- 需要本地初始化:必须为所有@State变量分配初始值,变量未初始化可能导致未定义的框架异常行为。
-- 创建自定义组件时支持通过状态变量名设置初始值:在创建组件实例时,可以通过变量名显式指定@State状态变量的初始值。
-
-**示例:**
-
-在下面的示例中:
-
-- 用户定义的组件MyComponent定义了@State状态变量count和title。如果count或title的值发生变化,则执行MyComponent的build方法来重新渲染组件;
-
-- EntryComponent中有多个MyComponent组件实例,第一个MyComponent内部状态的更改不会影响第二个MyComponent;
-
-- 创建MyComponent实例时通过变量名给组件内的变量进行初始化,如:
-
- ```ts
- MyComponent({ title: { value: 'Hello World 2' }, count: 7 })
- ```
-
-```ts
-// xxx.ets
-class Model {
- value: string
-
- constructor(value: string) {
- this.value = value
- }
-}
-
-@Entry
-@Component
-struct EntryComponent {
- build() {
- Column() {
- MyComponent({ count: 1, increaseBy: 2 }) // 第1个MyComponent实例
- MyComponent({ title: { value: 'Hello World 2' }, count: 7 }) // 第2个MyComponent实例
- }
- }
-}
-
-@Component
-struct MyComponent {
- @State title: Model = { value: 'Hello World' }
- @State count: number = 0
- private toggle: string = 'Hello World'
- private increaseBy: number = 1
-
- build() {
- Column() {
- Text(`${this.title.value}`).fontSize(30)
- Button('Click to change title')
- .margin(20)
- .onClick(() => {
- // 修改内部状态变量title
- this.title.value = (this.toggle == this.title.value) ? 'Hello World' : 'Hello ArkUI'
- })
-
- Button(`Click to increase count=${this.count}`)
- .margin(20)
- .onClick(() => {
- // 修改内部状态变量count
- this.count += this.increaseBy
- })
- }
- }
-}
-```
-
-
-## @Prop
-
-@Prop与@State有相同的语义,但初始化方式不同。@Prop装饰的变量必须使用其父组件提供的@State变量进行初始化,允许组件内部修改@Prop变量,但变量的更改不会通知给父组件,父组件变量的更改会同步到@prop装饰的变量,即@Prop属于单向数据绑定。
-
-@Prop状态数据具有以下特征:
-
-- 支持简单类型:仅支持number、string、boolean等简单数据类型;
-- 私有:仅支持组件内访问;
-- 支持多个实例:一个组件中可以定义多个标有@Prop的属性;
-- 创建自定义组件时将值传递给@Prop变量进行初始化:在创建组件的新实例时,必须初始化所有@Prop变量,不支持在组件内部进行初始化。
-
-**示例:**
-
-在下面的示例中,当按“+1”或“-1”按钮时,父组件状态发生变化,重新执行build方法,此时将创建一个新的CountDownComponent组件实例。父组件的countDownStartValue状态变量被用于初始化子组件的@Prop变量,当按下子组件的“count - costOfOneAttempt”按钮时,其@Prop变量count将被更改,CountDownComponent重新渲染,但是count值的更改不会影响父组件的countDownStartValue值。
-
-```ts
-// xxx.ets
-@Entry
-@Component
-struct ParentComponent {
- @State countDownStartValue: number = 10 // 初始化countDownStartValue
-
- build() {
- Column() {
- Text(`Grant ${this.countDownStartValue} nuggets to play.`).fontSize(18)
- Button('+1 - Nuggets in New Game')
- .margin(15)
- .onClick(() => {
- this.countDownStartValue += 1
- })
-
- Button('-1 - Nuggets in New Game')
- .margin(15)
- .onClick(() => {
- this.countDownStartValue -= 1
- })
- // 创建子组件时,必须在构造函数参数中提供其@Prop变量count的初始值,同时初始化常规变量costOfOneAttempt(非Prop变量)
- CountDownComponent({ count: this.countDownStartValue, costOfOneAttempt: 2 })
- }
- }
-}
-
-@Component
-struct CountDownComponent {
- @Prop count: number
- private costOfOneAttempt: number
-
- build() {
- Column() {
- if (this.count > 0) {
- Text(`You have ${this.count} Nuggets left`).fontSize(18)
- } else {
- Text('Game over!').fontSize(18)
- }
-
- Button('count - costOfOneAttempt')
- .margin(15)
- .onClick(() => {
- this.count -= this.costOfOneAttempt
- })
- }
- }
-}
-```
-
-
-## @Link
-
-@Link装饰的变量可以和父组件的@State变量建立双向数据绑定:
-
-- 支持多种类型:@Link支持的数据类型与@State相同,即class、number、string、boolean或这些类型的数组;
-- 私有:仅支持组件内访问;
-- 单个数据源:父组件中用于初始化子组件@Link变量的必须是父组件定义的状态变量;
-- 双向通信:子组件对@Link变量的更改将同步修改父组件中的@State变量;
-- 创建自定义组件时需要将变量的引用传递给@Link变量,在创建组件的新实例时,必须使用命名参数初始化所有@Link变量。@Link变量可以使用@State变量或@Link变量的引用进行初始化,@State变量可以通过`'$'`操作符创建引用。
-
-> **说明:**
->
-> @Link变量不能在组件内部进行初始化。
-
-**简单类型示例:**
-
-@Link语义是从`'$'`操作符引出,即`$isPlaying`是`this.isPlaying`内部状态的双向数据绑定。当单击子组件PlayButton中的按钮时,@Link变量更改,PlayButton与父组件中的Text和Button将同时进行刷新,同样地,当点击父组件中的Button修改`this.isPlaying`时,子组件PlayButton与父组件中的Text和Button也将同时刷新。
-
-```ts
-// xxx.ets
-@Entry
-@Component
-struct Player {
- @State isPlaying: boolean = false
-
- build() {
- Column() {
- PlayButton({ buttonPlaying: $isPlaying })
- Text(`Player is ${this.isPlaying ? '' : 'not'} playing`).fontSize(18)
- Button('Parent:' + this.isPlaying)
- .margin(15)
- .onClick(() => {
- this.isPlaying = !this.isPlaying
- })
- }
- }
-}
-
-@Component
-struct PlayButton {
- @Link buttonPlaying: boolean
-
- build() {
- Column() {
- Button(this.buttonPlaying ? 'pause' : 'play')
- .margin(20)
- .onClick(() => {
- this.buttonPlaying = !this.buttonPlaying
- })
- }
- }
-}
-```
-
-**复杂类型示例:**
-
-```ts
-// xxx.ets
-@Entry
-@Component
-struct Parent {
- @State arr: number[] = [1, 2, 3]
-
- build() {
- Column() {
- Child({ items: $arr })
- Button('Parent Button: splice')
- .margin(10)
- .onClick(() => {
- this.arr.splice(0, 1, 60)
- })
- ForEach(this.arr, item => {
- Text(item.toString()).fontSize(18).margin(10)
- }, item => item.toString())
- }
- }
-}
-
-
-@Component
-struct Child {
- @Link items: number[]
-
- build() {
- Column() {
- Button('Child Button1: push')
- .margin(15)
- .onClick(() => {
- this.items.push(100)
- })
- Button('Child Button2: replace whole item')
- .margin(15)
- .onClick(() => {
- this.items = [100, 200, 300]
- })
- }
- }
-}
-```
-
-**@Link、@State和@Prop结合使用示例:**
-
-下面示例中,ParentView包含ChildA和ChildB两个子组件,ParentView的状态变量counter分别用于初始化ChildA的@Prop变量和ChildB的@Link变量。
-
-- ChildB使用@Link建立双向数据绑定,当ChildB修改counterRef状态变量值时,该更改将同步到ParentView和ChildA共享;
-- ChildA使用@Prop建立从ParentView到自身的单向数据绑定,当ChildA修改counterVal状态变量值时,ChildA将重新渲染,但该更改不会传达给ParentView和ChildB。
-
-```ts
-// xxx.ets
-@Entry
-@Component
-struct ParentView {
- @State counter: number = 0
-
- build() {
- Column() {
- ChildA({ counterVal: this.counter })
- ChildB({ counterRef: $counter })
- }
- }
-}
-
-@Component
-struct ChildA {
- @Prop counterVal: number
-
- build() {
- Button(`ChildA: (${this.counterVal}) + 1`)
- .margin(15)
- .onClick(() => {
- this.counterVal += 1
- })
- }
-}
-
-@Component
-struct ChildB {
- @Link counterRef: number
-
- build() {
- Button(`ChildB: (${this.counterRef}) + 1`)
- .margin(15)
- .onClick(() => {
- this.counterRef += 1
- })
- }
-}
-```
-
-## @Observed和ObjectLink数据管理
-
-当开发者需要在子组件中针对父组件的一个变量(parent_a)设置双向同步时,开发者可以在父组件中使用@State装饰变量(parent_a),并在子组件中使用@Link装饰对应的变量(child_a)。这样不仅可以实现父组件与单个子组件之间的数据同步,也可以实现父组件与多个子组件之间的数据同步。如下图所示,可以看到,父子组件针对ClassA类型的变量设置了双向同步,那么当子组件1中变量对应的属性c的值变化时,会通知父组件同步变化,而当父组件中属性c的值变化时,会通知所有子组件同步变化。
-
-
-
-然而,上述例子是针对某个数据对象进行的整体同步,而当开发者只想针对父组件中某个数据对象的部分信息进行同步时,使用@Link就不能满足要求。如果这些部分信息是一个类对象,就可以使用@ObjectLink配合@Observed来实现,如下图所示。
-
-
-
-### 设置要求
-
-- @Observed用于类,@ObjectLink用于变量。
-
-- @ObjectLink装饰的变量类型必须为类(class type)。
- - 类要被@Observed装饰器所装饰。
- - 不支持简单类型参数,可以使用@Prop进行单向同步。
-
-- @ObjectLink装饰的变量是不可变的。
- - 属性的改动是被允许的,当改动发生时,如果同一个对象被多个@ObjectLink变量所引用,那么所有拥有这些变量的自定义组件都会被通知进行重新渲染。
-
-- @ObjectLink装饰的变量不可设置默认值。
- - 必须让父组件中有一个由@State、@Link、@StorageLink、@Provide或@Consume装饰的变量所参与的TS表达式进行初始化。
-
-- @ObjectLink装饰的变量是私有变量,只能在组件内访问。
-
-
-### 示例
-
-```ts
-// xxx.ets
-// 父组件ViewB中的类对象ClassA与子组件ViewA保持数据同步时,可以使用@ObjectLink和@Observed,绑定该数据对象的父组件和其他子组件同步更新
-var nextID: number = 0
-
-@Observed
-class ClassA {
- public name: string
- public c: number
- public id: number
-
- constructor(c: number, name: string = 'OK') {
- this.name = name
- this.c = c
- this.id = nextID++
- }
-}
-
-@Component
-struct ViewA {
- label: string = 'ViewA1'
- @ObjectLink a: ClassA
-
- build() {
- Row() {
- Button(`ViewA [${this.label}] this.a.c= ${this.a.c} +1`)
- .onClick(() => {
- this.a.c += 1
- })
- }.margin({ top: 10 })
- }
-}
-
-@Entry
-@Component
-struct ViewB {
- @State arrA: ClassA[] = [new ClassA(0), new ClassA(0)]
-
- build() {
- Column() {
- ForEach(this.arrA, (item) => {
- ViewA({ label: `#${item.id}`, a: item })
- }, (item) => item.id.toString())
- ViewA({ label: `this.arrA[first]`, a: this.arrA[0] })
- ViewA({ label: `this.arrA[last]`, a: this.arrA[this.arrA.length - 1] })
-
- Button(`ViewB: reset array`)
- .margin({ top: 10 })
- .onClick(() => {
- this.arrA = [new ClassA(0), new ClassA(0)]
- })
- Button(`ViewB: push`)
- .margin({ top: 10 })
- .onClick(() => {
- this.arrA.push(new ClassA(0))
- })
- Button(`ViewB: shift`)
- .margin({ top: 10 })
- .onClick(() => {
- this.arrA.shift()
- })
- }.width('100%')
- }
-}
-```
-
-
-## @Provide和@Consume
-
-@Provide作为数据的提供方,可以更新其子孙节点的数据,并触发页面渲染。@Consume在感知到@Provide数据的更新后,会触发当前自定义组件的重新渲染。
-
-> **说明:**
->
-> 使用@Provide和@Consume时应避免循环引用导致死循环。
-
-### @Provide
-
-| 名称 | 说明 |
-| -------------- | ------------------------------------------------------------ |
-| 装饰器参数 | 是一个string类型的常量,用于给装饰的变量起别名。如果规定别名,则提供对应别名的数据更新。如果没有,则使用变量名作为别名。推荐使用@Provide('alias')这种形式。 |
-| 同步机制 | @Provide的变量类似@State,可以修改对应变量进行页面重新渲染。也可以修改@Consume装饰的变量,反向修改@State变量。 |
-| 初始值 | 必须设置初始值。 |
-| 页面重渲染场景 | 触发页面渲染的修改:
- 基础类型(boolean,string,number)变量的改变;
- @Observed class类型变量及其属性的修改;
- 添加,删除,更新数组中的元素。 |
-
-### @Consume
-
-| 类型 | 说明 |
-| ------ | ---------------- |
-| 初始值 | 不可设置默认初始值。 |
-
-### 示例
-
-```ts
-// xxx.ets
-@Entry
-@Component
-struct CompA {
- @Provide("reviewVote") reviewVotes: number = 0;
-
- build() {
- Column() {
- CompB()
- Button(`CompA: ${this.reviewVotes}`)
- .margin(10)
- .onClick(() => {
- this.reviewVotes += 1;
- })
- }
- }
-}
-
-@Component
-struct CompB {
- build() {
- Column() {
- CompC()
- }
- }
-}
-
-@Component
-struct CompC {
- @Consume("reviewVote") reviewVotes: number
-
- build() {
- Column() {
- Button(`CompC: ${this.reviewVotes}`)
- .margin(10)
- .onClick(() => {
- this.reviewVotes += 1
- })
- }.width('100%')
- }
-}
-```
-
-## @Watch
-
-@Watch用于监听状态变量的变化,语法结构为:
-
-```ts
-@State @Watch("onChanged") count : number = 0
-```
-
-如上所示,给状态变量增加一个@Watch装饰器,通过@Watch注册一个回调方法onChanged, 当状态变量count被改变时, 触发onChanged回调。
-
-装饰器@State、@Prop、@Link、@ObjectLink、@Provide、@Consume、@StorageProp以及@StorageLink所装饰的变量均可以通过@Watch监听其变化。
-
-
-> **说明:**
->
-> 深层次数据修改不会触发@Watch回调,例如无法监听数组中对象值的改变。
-
-```ts
-// xxx.ets
-@Entry
-@Component
-struct CompA {
- @State @Watch('onBasketUpdated') shopBasket: Array = [7, 12, 47, 3]
- @State totalPurchase: number = 0
- @State addPurchase: number = 0
-
- aboutToAppear() {
- this.updateTotal()
- }
-
- updateTotal(): void {
- let sum = 0;
- this.shopBasket.forEach((i) => {
- sum += i
- })
- // 计算新的购物篮总价值,如果超过100,则适用折扣
- this.totalPurchase = (sum < 100) ? sum : 0.9 * sum
- return this.totalPurchase
- }
-
- // shopBasket更改时触发该方法
- onBasketUpdated(propName: string): void {
- this.updateTotal()
- }
-
- build() {
- Column() {
- Button('add to basket ' + this.addPurchase)
- .margin(15)
- .onClick(() => {
- this.addPurchase = Math.round(100 * Math.random())
- this.shopBasket.push(this.addPurchase)
- })
- Text(`${this.totalPurchase}`)
- .fontSize(30)
- }
- }
-}
-```
\ No newline at end of file
diff --git a/zh-cn/application-dev/quick-start/arkts-state.md b/zh-cn/application-dev/quick-start/arkts-state.md
new file mode 100644
index 0000000000000000000000000000000000000000..50cc33b3bf26e654dbb3db5ef408533e8a85fc8d
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-state.md
@@ -0,0 +1,261 @@
+# \@State:组件内状态
+
+
+\@State装饰的变量,或称为状态变量,一旦变量拥有了状态属性,就和自定义组件的渲染绑定起来。当状态改变时,UI会发生对应的渲染改变。
+
+
+在状态变量相关装饰器中,\@State是最基础的,使变量拥有状态属性的装饰器,它也是大部分状态变量的数据源。
+
+
+> **说明:**
+>
+> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+
+## 概述
+
+\@State装饰的变量,与声明式范式中的其他被装饰变量一样,是私有的,只能从组件内部访问,在声明时必须指定其类型和本地初始化。初始化也可选择使用命名参数机制从父组件完成初始化。
+
+\@State装饰的变量拥有以下特点:
+
+- \@State装饰的变量与子组件中的\@Prop、\@Link或\@ObjectLink装饰变量之间建立单向或双向数据同步。
+
+- \@State装饰的变量生命周期与其所属自定义组件的生命周期相同。
+
+
+## 装饰器使用规则说明
+
+| \@State变量装饰器 | 说明 |
+| ------------ | ---------------------------------------- |
+| 装饰器参数 | 无 |
+| 同步类型 | 不与父组件中任何类型的变量同步。 |
+| 允许装饰的变量类型 | Object、class、string、number、boolean、enum类型,以及这些类型的数组。嵌套类型的场景请参考[观察变化](#观察变化)。
类型必须被指定。
不支持any,不支持简单类型和复杂类型的联合类型,不允许使用undefined和null。
**说明:**
建议不要装饰Date类型,应用可能会产生异常行为。
不支持Length、ResourceStr、ResourceColor类型,Length、ResourceStr、ResourceColor为简单类型和复杂类型的联合类型。 |
+| 被装饰变量的初始值 | 必须指定。 |
+
+
+## 变量的传递/访问规则说明
+
+| 传递/访问 | 说明 |
+| --------- | ---------------------------------------- |
+| 从父组件初始化 | 可选,从父组件初始化或者本地初始化。
支持父组件中常规变量、\@State、\@Link、\@Prop、\@Provide、\@Consume、\@ObjectLink、\@StorageLink、\@StorageProp、\@LocalStorageLink和\@LocalStorageProp装饰的变量,初始化子组件的\@State。 |
+| 用于初始化子组件 | \@State装饰的变量支持初始化子组件的常规变量、\@State、\@Link、\@Prop、\@Provide。 |
+| 是否支持组件外访问 | 不支持,只能在组件内访问。 |
+
+ **图1** 初始化规则图示
+
+
+
+
+## 观察变化和行为表现
+
+并不是状态变量的所有更改都会引起UI的刷新,只有可以被框架观察到的修改才会引起UI刷新。该小节去介绍什么样的修改才能被观察到,以及观察到变化后,框架的是怎么引起UI刷新的,即框架的行为表现是什么。
+
+
+### 观察变化
+
+- 当装饰的数据类型为boolean、string、number类型时,可以观察到数值的变化。
+
+ ```ts
+ // for simple type
+ @State count: number = 0;
+ // value changing can be observed
+ this.count = 1;
+ ```
+
+- 当装饰的数据类型为class或者Object时,可以观察到自身的赋值的变化,和其属性赋值的变化,即Object.keys(observedObject)返回的所有属性。例子如下。
+ 声明ClassA和Model类。
+
+ ```ts
+ class ClassA {
+ public value: string;
+
+ constructor(value: string) {
+ this.value = value;
+ }
+ }
+
+ class Model {
+ public value: string;
+ public name: ClassA;
+ constructor(value: string, a: ClassA) {
+ this.value = value;
+ this.name = a;
+ }
+ }
+ ```
+
+ \@State装饰的类型是Model
+
+ ```ts
+ // class类型
+ @State title: Model = new Model('Hello', new ClassA('World'));
+ ```
+
+ 对\@State装饰变量的赋值。
+
+ ```ts
+ // class类型赋值
+ this.title = new Model('Hi', new ClassA('ArkUI'));
+ ```
+
+ 对\@State装饰变量的属性赋值。
+
+ ```ts
+ // class属性的赋值
+ this.title.value = 'Hi'
+ ```
+
+ 嵌套属性的赋值观察不到。
+
+ ```ts
+ // 嵌套的属性赋值观察不到
+ this.title.name.value = 'ArkUI'
+ ```
+- 当装饰的对象是array时,可以观察到数组本身的赋值和添加、删除、更新数组的变化。例子如下。
+ 声明ClassA和Model类。
+
+ ```ts
+ class Model {
+ public value: number;
+ constructor(value: number) {
+ this.value = value;
+ }
+ }
+ ```
+
+ \@State装饰的对象为Model类型数组时。
+
+ ```ts
+ @State title: Model[] = [new Model(11), new Model(1)]
+ ```
+
+ 数组自身的赋值可以观察到。
+
+ ```ts
+ this.title = [new Model(2)]
+ ```
+
+ 数组项的赋值可以观察到。
+
+ ```ts
+ this.title[0] = new Model(2)
+ ```
+
+ 删除数组项可以观察到。
+
+ ```ts
+ this.title.pop()
+ ```
+
+ 新增数组项可以观察到。
+
+ ```ts
+ this.title.push(new Model(12))
+ ```
+
+
+### 框架行为
+
+- 当状态变量被改变时,查询依赖该状态变量的组件;
+
+- 执行依赖该状态变量的组件的更新方法,组件更新渲染;
+
+- 和该状态变量不相关的组件或者UI描述不会发生重新渲染,从而实现页面渲染的按需更新。
+
+
+## 使用场景
+
+
+### 装饰简单类型的变量
+
+以下示例为\@State装饰的简单类型,count被\@State装饰成为状态变量,count的改变引起Button组件的刷新:
+
+- 当状态变量count改变时,查询到只有Buttont组件关联了它;
+
+- 执行Button组件的更新方法,实现按需刷新。
+
+
+```ts
+@Entry
+@Component
+struct MyComponent {
+ @State count: number = 0;
+
+ build() {
+ Button(`click times: ${this.count}`)
+ .onClick(() => {
+ this.count += 1;
+ })
+ }
+}
+```
+
+
+### 装饰class对象类型的变量
+
+- 自定义组件MyComponent定义了被\@State装饰的状态变量count和title,其中title的类型为自定义类Model。如果count或title的值发生变化,则查询MyComponent中使用该状态变量的UI组件,并进行重新渲染。
+
+- EntryComponent中有多个MyComponent组件实例,第一个MyComponent内部状态的更改不会影响第二个MyComponent。
+
+
+
+```ts
+class Model {
+ public value: string;
+
+ constructor(value: string) {
+ this.value = value;
+ }
+}
+
+@Entry
+@Component
+struct EntryComponent {
+ build() {
+ Column() {
+ // 此处指定的参数都将在初始渲染时覆盖本地定义的默认值,并不是所有的参数都需要从父组件初始化
+ MyComponent({ count: 1, increaseBy: 2 })
+ MyComponent({ title: new Model('Hello, World 2'), count: 7 })
+ }
+ }
+}
+
+@Component
+struct MyComponent {
+ @State title: Model = new Model('Hello World');
+ @State count: number = 0;
+ private increaseBy: number = 1;
+
+ build() {
+ Column() {
+ Text(`${this.title.value}`)
+ Button(`Click to change title`).onClick(() => {
+ // @State变量的更新将触发上面的Text组件内容更新
+ this.title.value = this.title.value === 'Hello ArkUI' ? 'Hello World' : 'HelloArkUI';
+ })
+
+ Button(`Click to increase count=${this.count}`).onClick(() => {
+ // @State变量的更新将触发上面的Text组件内容更新
+ this.count += this.increaseBy;
+ })
+ }
+ }
+}
+```
+
+
+从该示例中,我们可以了解到\@State变量首次渲染的初始化流程:
+
+
+1. 使用默认的本地初始化:
+
+ ```ts
+ @State title: Model = new Model('Hello World');
+ @State count: number = 0;
+ ```
+
+2. 对于\@State来说,命名参数机制传递的值并不是必选的,如果没有命名参数传值,则使用本地初始化的默认值:
+
+ ```ts
+ MyComponent({ count: 1, increaseBy: 2 })
+ ```
diff --git a/zh-cn/application-dev/quick-start/arkts-statestyles.md b/zh-cn/application-dev/quick-start/arkts-statestyles.md
new file mode 100644
index 0000000000000000000000000000000000000000..171d0e0ad3445ed5d8ea4c3c0f65e0a6c8b8f5e6
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-statestyles.md
@@ -0,0 +1,128 @@
+# stateStyles:多态样式
+
+
+\@Styles和\@Extend仅仅应用于静态页面的样式复用,stateStyles可以依据组件的内部状态的不同,快速设置不同样式。这就是我们本章要介绍的内容stateStyles(又称为:多态样式)。
+
+
+## 概述
+
+stateStyles是属性方法,可以根据UI内部状态来设置样式,类似于css伪类,但语法不同。ArkUI提供以下四种状态:
+
+- focused:获焦态。
+
+- normal:正常态。
+
+- pressed:按压态。
+
+- disabled:不可用态。
+
+
+## 使用场景
+
+
+### 基础场景
+
+下面的示例展示了stateStyles最基本的使用场景。Button处于第一个组件,默认获焦,生效focused指定的粉色样式。按压时显示为pressed态指定的黑色。如果在Button前再放一个组件,使其不处于获焦态,就会生效normal态的黄色。
+
+
+```ts
+@Entry
+@Component
+struct StateStylesSample {
+ build() {
+ Column() {
+ Button('Click me')
+ .stateStyles({
+ focused: {
+ .backgroundColor(Color.Pink)
+ },
+ pressed: {
+ .backgroundColor(Color.Black)
+ },
+ normal: {
+ .backgroundColor(Color.Yellow)
+ }
+ })
+ }.margin('30%')
+ }
+}
+```
+
+
+ **图1** 获焦态和按压态
+
+
+
+
+### \@Styles和stateStyles联合使用
+
+以下示例通过\@Styles指定stateStyles的不同状态。
+
+
+
+```ts
+@Entry
+@Component
+struct MyComponent {
+ @Styles normalStyle() {
+ .backgroundColor(Color.Gray)
+ }
+
+ @Styles pressedStyle() {
+ .backgroundColor(Color.Red)
+ }
+
+ build() {
+ Column() {
+ Text('Text1')
+ .fontSize(50)
+ .fontColor(Color.White)
+ .stateStyles({
+ normal: this.normalStyle,
+ pressed: this.pressedStyle,
+ })
+ }
+ }
+}
+```
+
+ **图2** 正常态和按压态
+
+
+
+
+### 在stateStyles里使用常规变量和状态变量
+
+stateStyles可以通过this绑定组件内的常规变量和状态变量。
+
+
+```ts
+@Entry
+@Component
+struct CompWithInlineStateStyles {
+ @State focusedColor: Color = Color.Red;
+ normalColor: Color = Color.Green
+
+ build() {
+ Button('clickMe').height(100).width(100)
+ .stateStyles({
+ normal: {
+ .backgroundColor(this.normalColor)
+ },
+ focused: {
+ .backgroundColor(this.focusedColor)
+ }
+ })
+ .onClick(() => {
+ this.focusedColor = Color.Pink
+ })
+ .margin('30%')
+ }
+}
+```
+
+Button默认获焦显示红色,点击事件触发后,获焦态变为粉色。
+
+ **图3** 点击改变获焦态样式
+
+
diff --git a/zh-cn/application-dev/quick-start/arkts-style.md b/zh-cn/application-dev/quick-start/arkts-style.md
new file mode 100644
index 0000000000000000000000000000000000000000..04a862b4a6c13dd6386738971e8630b883707e2b
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-style.md
@@ -0,0 +1,104 @@
+# \@Styles:定义组件重用样式
+
+
+如果每个组件的样式都需要单独设置,在开发过程中会出现大量代码在进行重复样式设置,虽然可以复制粘贴,但为了代码简洁性和后续方便维护,我们推出了可以提炼公共样式进行复用的装饰器\@Styles。
+
+
+\@Styles装饰器可以将多条样式设置提炼成一个方法,直接在组件声明的位置调用。通过\@Styles装饰器可以快速定义并复用自定义样式。用于快速定义并复用自定义样式。
+
+
+> **说明:**
+>
+> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+
+## 装饰器使用说明
+
+- 当前\@Styles仅支持[通用属性](../reference/arkui-ts/ts-universal-attributes-size.md)和[通用事件](../reference/arkui-ts/ts-universal-events-click.md)。
+
+- \@Styles方法不支持参数,反例如下。
+
+ ```ts
+ // 反例: @Styles不支持参数
+ @Styles function globalFancy (value: number) {
+ .width(value)
+ }
+ ```
+
+- \@Styles可以定义在组件内或全局,在全局定义时需在方法名前面添加function关键字,组件内定义时则不需要添加function关键字。
+
+ ```ts
+ // 全局
+ @Styles function functionName() { ... }
+
+ // 在组件内
+ @Component
+ struct FancyUse {
+ @Styles fancy() {
+ .height(100)
+ }
+ }
+ ```
+
+- 定义在组件内的\@Styles可以通过this访问组件的常量和状态变量,并可以在\@Styles里通过事件来改变状态变量的值,示例如下:
+
+ ```ts
+ @Component
+ struct FancyUse {
+ @State heightVlaue: number = 100
+ @Styles fancy() {
+ .height(this.heightVlaue)
+ .backgroundColor(Color.Yellow)
+ .onClick(() => {
+ this.heightVlaue = 200
+ })
+ }
+ }
+ ```
+
+- 组件内\@Styles的优先级高于全局\@Styles。
+ 框架优先找当前组件内的\@Styles,如果找不到,则会全局查找。
+
+
+## 使用场景
+
+以下示例中演示了组件内\@Styles和全局\@Styles的用法。
+
+
+
+```ts
+// 定义在全局的@Styles封装的样式
+@Styles function globalFancy () {
+ .width(150)
+ .height(100)
+ .backgroundColor(Color.Pink)
+}
+
+@Entry
+@Component
+struct FancyUse {
+ @State heightVlaue: number = 100
+ // 定义在组件内的@Styles封装的样式
+ @Styles fancy() {
+ .width(200)
+ .height(this.heightVlaue)
+ .backgroundColor(Color.Yellow)
+ .onClick(() => {
+ this.heightVlaue = 200
+ })
+ }
+
+ build() {
+ Column({ space: 10 }) {
+ // 使用全局的@Styles封装的样式
+ Text('FancyA')
+ .globalFancy ()
+ .fontSize(30)
+ // 使用全局的@Styles封装的样式
+ Text('FancyB')
+ .fancy()
+ .fontSize(30)
+ }
+ }
+}
+```
diff --git a/zh-cn/application-dev/quick-start/arkts-two-way-sync.md b/zh-cn/application-dev/quick-start/arkts-two-way-sync.md
new file mode 100644
index 0000000000000000000000000000000000000000..c48a7a148efe5169278de9224faa8da0f84926df
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-two-way-sync.md
@@ -0,0 +1,47 @@
+# $语法:内置组件双向同步
+
+
+$$运算符为系统内置组件提供TS变量的引用,使得TS变量和系统内置组件的内部状态保持同步。
+
+
+内部状态具体指什么取决于组件。例如,[bindPopup](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-popup.md)属性方法的show参数。
+
+
+## 使用规则
+
+- 当前$$支持基础类型变量,以及\@State、\@Link和\@Prop装饰的变量。
+
+- 当前$$仅支持[bindPopup](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-popup.md)属性方法的show参数,[Radio](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-radio.md)组件的checked属性,[Refresh](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-refresh.md)组件的refreshing参数。
+
+- $$绑定的变量变化时,会触发UI的同步刷新。
+
+
+## 使用示例
+
+以[bindPopup](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-popup.md)属性方法的show参数为例:
+
+
+```ts
+// xxx.ets
+@Entry
+@Component
+struct bindPopupPage {
+ @State customPopup: boolean = false;
+
+ build() {
+ Column() {
+ Button('Popup')
+ .margin(20)
+ .onClick(() => {
+ this.customPopup = !this.customPopup
+ })
+ .bindPopup($$this.customPopup, {
+ message: 'showPopup'
+ })
+ }
+ }
+}
+```
+
+
+
diff --git a/zh-cn/application-dev/quick-start/arkts-watch.md b/zh-cn/application-dev/quick-start/arkts-watch.md
new file mode 100644
index 0000000000000000000000000000000000000000..b1dbbfb0e395c8e7e628783635cb899e0468992a
--- /dev/null
+++ b/zh-cn/application-dev/quick-start/arkts-watch.md
@@ -0,0 +1,175 @@
+# \@Watch:状态变量更改通知
+
+
+\@Watch应用于对状态变量的监听。如果开发者需要关注某个状态变量的值是否改变,可以使用\@Watch为状态变量设置回调函数。
+
+
+> **说明:**
+>
+> 从API version 9开始,该装饰器支持在ArkTS卡片中使用。
+
+
+## 概述
+
+\@Watch用于监听状态变量的变化,当状态变量变化时,\@Watch的回调方法将被调用。\@Watch在ArkUI框架内部判断数值有无更新使用的是严格相等(===),遵循严格相等规范。当在严格相等为false的情况下,就会触发\@Watch的回调。
+
+
+## 装饰器说明
+
+| \@Watch补充变量装饰器 | 说明 |
+| -------------- | ---------------------------------------- |
+| 装饰器参数 | 必填。常量字符串,字符串需要有引号。是(string) => void自定义成员函数的方法的引用。 |
+| 可装饰的自定义组件变量 | 可监听所有装饰器装饰的状态变量。不允许监听常规变量。 |
+| 装饰器的顺序 | 建议\@State、\@Prop、\@Link等装饰器在\@Watch装饰器之前。 |
+
+
+## 语法说明
+
+| 类型 | 说明 |
+| ---------------------------------------- | ---------------------------------------- |
+| (changedPropertyName? : string) => void | 该函数是自定义组件的成员函数,changedPropertyName是被watch的属性名。
在多个状态变量绑定同一个\@Watch的回调方法的时候,可以通过changedPropertyName进行不同的逻辑处理
将属性名作为字符串输入参数,不返回任何内容。 |
+
+
+## 观察变化和行为表现
+
+1. 当观察到状态变量的变化(包括双向绑定的AppStorage和LocalStorage中对应的key发生的变化)的时候,对应的\@Watch的回调方法将被触发;
+
+2. \@Watch方法在自定义组件的属性变更之后同步执行;
+
+3. 如果在\@Watch的方法里改变了其他的状态变量,也会引起的状态变更和\@Watch的执行;
+
+4. 在第一次初始化的时候,\@Watch装饰的方法不会被调用,即认为初始化不是状态变量的改变。只有在后续状态改变时,才会调用\@Watch回调方法。
+
+
+## 限制条件
+
+- 建议开发者避免无限循环。循环可能是因为在\@Watch的回调方法里直接或者间接地修改了同一个状态变量引起的。为了避免循环的产生,建议不要在\@Watch的回调方法里修改当前装饰的状态变量;
+
+- 开发者应关注性能,属性值更新函数会延迟组件的重新渲染(具体请见上面的行为表现),因此,回调函数应仅执行快速运算;
+
+- 不建议在\@Watch函数中调用async await,因为\@Watch设计的用途是为了快速的计算,异步行为可能会导致重新渲染速度的性能问题。
+
+
+## 使用场景
+
+
+### \@Watch与\@Link组合使用
+
+以下示例说明了如何在子组件中观察\@Link变量。
+
+
+```ts
+class PurchaseItem {
+ static NextId: number = 0;
+ public id: number;
+ public price: number;
+
+ constructor(price: number) {
+ this.id = PurchaseItem.NextId++;
+ this.price = price;
+ }
+}
+
+@Component
+struct BasketViewer {
+ @Link @Watch('onBasketUpdated') shopBasket: PurchaseItem[];
+ @State totalPurchase: number = 0;
+
+ updateTotal(): number {
+ let total = this.shopBasket.reduce((sum, i) => sum + i.price, 0);
+ // 超过100欧元可享受折扣
+ if (total >= 100) {
+ total = 0.9 * total;
+ }
+ return total;
+ }
+ // @Watch 回调
+ onBasketUpdated(propName: string): void {
+ this.totalPurchase = this.updateTotal();
+ }
+
+ build() {
+ Column() {
+ ForEach(this.shopBasket,
+ (item) => {
+ Text(`Price: ${item.price.toFixed(2)} €`)
+ },
+ item => item.id.toString()
+ )
+ Text(`Total: ${this.totalPurchase.toFixed(2)} €`)
+ }
+ }
+}
+
+@Entry
+@Component
+struct BasketModifier {
+ @State shopBasket: PurchaseItem[] = [];
+
+ build() {
+ Column() {
+ Button('Add to basket')
+ .onClick(() => {
+ this.shopBasket.push(new PurchaseItem(Math.round(100 * Math.random())))
+ })
+ BasketViewer({ shopBasket: $shopBasket })
+ }
+ }
+}
+```
+
+处理步骤如下:
+
+1. BasketModifier组件的Button.onClick向BasketModifier shopBasket中添加条目;
+
+2. \@Link装饰的BasketViewer shopBasket值发生变化;
+
+3. 状态管理框架调用\@Watch函数BasketViewer onBasketUpdated 更新BaketViewer TotalPurchase的值;
+
+4. \@Link shopBasket的改变,新增了数组项,ForEach组件会执行item Builder,渲染构建新的Item项;\@State totalPurchase改变,对应的Text组件也重新渲染;重新渲染是异步发生的。
+
+
+### \@Watch和自定义组件更新
+
+以下示例展示组件更新和\@Watch的处理步骤。count在两个组件中均由\@State装饰。
+
+
+```ts
+@Component
+struct TotalView {
+ @Prop @Watch('onCountUpdated') count: number;
+ @State total: number = 0;
+ // @Watch cb
+ onCountUpdated(propName: string): void {
+ this.total += this.count;
+ }
+
+ build() {
+ Text(`Total: ${this.total}`)
+ }
+}
+
+@Entry
+@Component
+struct CountModifier {
+ @State count: number = 0;
+
+ build() {
+ Column() {
+ Button('add to basket')
+ .onClick(() => {
+ this.count++
+ })
+ TotalView({ count: this.count })
+ }
+ }
+}
+```
+
+处理步骤:
+
+1. CountModifier自定义组件的Button.onClick点击事件自增count。
+
+2. 由于\@State count变量更改,子组件TotalView中的\@Prop被更新,其\@Watch('onCountUpdated')方法被调用,更新了子组件TotalView 中的total变量。
+
+3. 子组件TotalView中的Text重新渲染。
diff --git a/zh-cn/application-dev/quick-start/figures/01.png b/zh-cn/application-dev/quick-start/figures/01.png
deleted file mode 100644
index 8342856ec6643e20a941187852e6aef3ead11010..0000000000000000000000000000000000000000
Binary files a/zh-cn/application-dev/quick-start/figures/01.png and /dev/null differ
diff --git a/zh-cn/application-dev/quick-start/figures/CoreSpec_figures_state-mgmt-overview.png b/zh-cn/application-dev/quick-start/figures/CoreSpec_figures_state-mgmt-overview.png
deleted file mode 100644
index 37ae5324808a0ab50f210907ca65a09e4456a371..0000000000000000000000000000000000000000
Binary files a/zh-cn/application-dev/quick-start/figures/CoreSpec_figures_state-mgmt-overview.png and /dev/null differ
diff --git a/zh-cn/application-dev/quick-start/figures/Video_2023-03-06_152548.gif b/zh-cn/application-dev/quick-start/figures/Video_2023-03-06_152548.gif
new file mode 100644
index 0000000000000000000000000000000000000000..c5cd5839d7eebfea2b10d06f197e7caddc30f61c
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/Video_2023-03-06_152548.gif differ
diff --git a/zh-cn/application-dev/quick-start/figures/Video_2023-03-17_120758.gif b/zh-cn/application-dev/quick-start/figures/Video_2023-03-17_120758.gif
new file mode 100644
index 0000000000000000000000000000000000000000..500d179cd0a05e73a65047711a03c25fac596ba2
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/Video_2023-03-17_120758.gif differ
diff --git a/zh-cn/application-dev/quick-start/figures/Video_2023-03-17_144605.gif b/zh-cn/application-dev/quick-start/figures/Video_2023-03-17_144605.gif
new file mode 100644
index 0000000000000000000000000000000000000000..d48d7a7d7e0370acaf85fdc9164b526c69397a5d
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/Video_2023-03-17_144605.gif differ
diff --git a/zh-cn/application-dev/quick-start/figures/Video_2023-03-17_144824.gif b/zh-cn/application-dev/quick-start/figures/Video_2023-03-17_144824.gif
new file mode 100644
index 0000000000000000000000000000000000000000..f4437b3e2c92eaaa6ed7cd6daf508939b8d8ec99
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/Video_2023-03-17_144824.gif differ
diff --git a/zh-cn/application-dev/quick-start/figures/arkts-basic-grammar.png b/zh-cn/application-dev/quick-start/figures/arkts-basic-grammar.png
new file mode 100644
index 0000000000000000000000000000000000000000..3f1c355759a60d5d2bca9166776ff3000b947796
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/arkts-basic-grammar.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/arkts-get-started.png b/zh-cn/application-dev/quick-start/figures/arkts-get-started.png
deleted file mode 100644
index 21de3f9615767dfb3e50fc5a0e1707eb87dfb73d..0000000000000000000000000000000000000000
Binary files a/zh-cn/application-dev/quick-start/figures/arkts-get-started.png and /dev/null differ
diff --git a/zh-cn/application-dev/quick-start/figures/restrictions-data-type-declarations.gif b/zh-cn/application-dev/quick-start/figures/restrictions-data-type-declarations.gif
deleted file mode 100644
index b00b7fad991682b2cd81b0afdd149a3b7f73dc49..0000000000000000000000000000000000000000
Binary files a/zh-cn/application-dev/quick-start/figures/restrictions-data-type-declarations.gif and /dev/null differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001206450834.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001206450834.png
deleted file mode 100644
index 35a5db40879212c9d90e5a02bba02e49e1158c8f..0000000000000000000000000000000000000000
Binary files a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001206450834.png and /dev/null differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001251090821.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001251090821.png
deleted file mode 100644
index 69aec480939a34e310d8fbeead6a8e33644bb11b..0000000000000000000000000000000000000000
Binary files a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001251090821.png and /dev/null differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001501936014.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001501936014.png
new file mode 100644
index 0000000000000000000000000000000000000000..7f6f1aa654cee34259ae3699a4eb82a5fa4bedf6
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001501936014.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001501938718.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001501938718.png
new file mode 100644
index 0000000000000000000000000000000000000000..2b133e6c4b8fa5ddd176dde3566ac2fa1aae635f
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001501938718.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502091796.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502091796.png
new file mode 100644
index 0000000000000000000000000000000000000000..1f66ecd249d5ec2570288f0a4c2d44848d3fae44
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502091796.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502092556.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502092556.png
new file mode 100644
index 0000000000000000000000000000000000000000..e7b56752fed8e17502a7685d172cf796f213cbb7
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502092556.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502094666.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502094666.png
new file mode 100644
index 0000000000000000000000000000000000000000..c0503a81e37bb673026af6da01c06853531c11bd
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502094666.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502255262.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502255262.png
new file mode 100644
index 0000000000000000000000000000000000000000..c4715b0d8616e163f5bed207cf5732ba360f307f
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502255262.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502372786.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502372786.png
new file mode 100644
index 0000000000000000000000000000000000000000..b67f19d236bc4684e8eb1802b249e4096398b9ba
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502372786.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502704640.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502704640.png
new file mode 100644
index 0000000000000000000000000000000000000000..3bc469d94558ec8c6637d01423e33b053eeaa557
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001502704640.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552614217.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552614217.png
new file mode 100644
index 0000000000000000000000000000000000000000..e011bf227710e2796bbc6cc075066e608c0d83f5
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552614217.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552855957.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552855957.png
new file mode 100644
index 0000000000000000000000000000000000000000..0d81f1ac85bf11bc8d593e677cb284309e39ae8b
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552855957.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552972029.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552972029.png
new file mode 100644
index 0000000000000000000000000000000000000000..38c0cfa6f39685d47eb47da8b6a522bf68c2a602
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552972029.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552978157.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552978157.png
new file mode 100644
index 0000000000000000000000000000000000000000..13c73e874103d7bc798154d8bdcfde1a8b298e5c
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001552978157.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001553348833.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001553348833.png
new file mode 100644
index 0000000000000000000000000000000000000000..3f1eb07e78b2cb1234c50fb9eda495dd3f5f2001
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001553348833.png differ
diff --git a/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001562352677.png b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001562352677.png
new file mode 100644
index 0000000000000000000000000000000000000000..64e710ea9ea0fe8e484d262c9260600b01ffd00a
Binary files /dev/null and b/zh-cn/application-dev/quick-start/figures/zh-cn_image_0000001562352677.png differ