页面级变量的状态管理
装饰器 | 装饰内容 | 说明 |
---|---|---|
@State | 基本数据类型,类,数组 | 修饰的状态数据被修改时会触发组件的build方法进行UI界面更新。 |
@Prop | 基本数据类型 | 修改后的状态数据用于在父组件和子组件之间建立单向数据依赖关系。修改父组件关联数据时,当前组件会重新渲染。 |
@Link | 基本数据类型,类,数组 | 父子组件之间的双向数据绑定,父组件的内部状态数据作为数据源,任何一方所做的修改都会反映给另一方。 |
@Observed | 类 | @Observed应用于类,表示该类中的数据变更被UI页面管理。 |
@ObjectLink | 被@Observed所装饰类的对象 | @ObjectLink装饰的状态数据被修改时,在父组件或者其他兄弟组件内与它关联的状态数据所在的组件都会重新渲染。 |
@Provide | 基本数据类型,类,数组 | @Provide作为数据的提供方,可以更新其子孙节点的数据,并触发页面重新渲染。 |
@Consume | 基本数据类型,类,数组 | @Consume装饰的变量在感知到@Provide装饰的变量更新后,会触发当前自定义组件的重新渲染。 |
@State
组件内数据,改变时,只会调用自己的build进行UI刷新;并且为私有变量,只能在组件内访问
@Prop
@Prop装饰的变量必须使用其父组件提供的@State变量进行初始化,单向绑定,组件内部改变不会通知父组件,父组件改变会通知组件
@Link
@Link装饰的变量必须使用其父组件提供的@State变量进行初始化,双向绑定,组件内部改变会通知父组件,父组件改变也会通知组件
@Observed和ObjectLink数据管理
@Observed用于类,@ObjectLink装饰的变量类型也必须为类;@ObjectLink装饰的变量不可设置默认值,必须让父组件中有一个由@State、@Link、@StorageLink、@Provide或@Consume装饰的变量所参与的TS表达式进行初始化。这里是一绑n且双向,任何一个组件的数据发生,都会通知所有被绑定的组件。还有与@Provide和@Consume不同的时这里的数据时由UI页面管理的
@Provide和@Consume
@Provide作为数据的提供方,可以更新其子孙节点的数据,并触发页面渲染。@Consume在感知到@Provide数据的更新后,会触发当前自定义组件的重新渲染,同时@Consume改变数据,也会被@Provide感知到,从而触发所有拥有该数据的组件的重新渲染。这里也是一绑n且双向,而且数据类型不局限于类
@Watch
@Watch用于监听状态变量的变化,语法结构为:
@State @Watch("onChanged") count : number = 0
通过@Watch注册一个回调方法onChanged,当count数据发生改变时,触发onChanged回调
应用级变量的状态管理
装饰器 | 说明 |
---|---|
@StorageLink | @StorageLink(name)的原理类似于@Consume(name),不同的是,该给定名称的链接对象是从AppStorage中获得的,在UI组件和AppStorage之间建立双向绑定同步数据。 |
@StorageProp | @StorageProp(name)将UI组件数据与AppStorage进行单向同步,AppStorage中值的更改会更新UI组件中的数据,但UI组件无法更改AppStorage中的数据。 |
@LocalStorageLink | 组件通过使用@LocalStorageLink(key)装饰的状态变量,key值为LocalStorage中的属性键值,与LocalStorage建立双向数据绑定。 |
@LocalStorageProp | 组件通过使用@LocalStorageProp(key)装饰的状态变量,key值为LocalStorage中的属性键值,与LocalStorage建立单向数据绑定。 |
@StorageLink装饰器
组件通过使用@StorageLink(key)装饰的状态变量,与AppStorage建立双向数据绑定,key为AppStorage中的属性键值。当创建包含@StorageLink的状态变量的组件时,该状态变量的值将使用AppStorage中的值进行初始化。在UI组件中对@StorageLink的状态变量所做的更改将同步到AppStorage,并从AppStorage同步到任何其他绑定实例中,如PersistentStorage或其他绑定的UI组件。
作用与@Link类似,不同的是对象变成了组件数据绑定到AppStorage中,双向绑定且是一对多;而绑定的数值由第一个建立绑定的组件确定,然后任意更改一处数据,都会导致全局发生改变。
@StorageProp装饰器
组件通过使用@StorageProp(key)装饰的状态变量,与AppStorage建立单向数据绑定,key标识AppStorage中的属性键值。当创建包含@StorageProp的状态变量的组件时,该状态变量的值将使用AppStorage中的值进行初始化。AppStorage中属性值的更改会导致绑定该状态变量的UI组件进行状态更新。
作用与@Prop类似,对象变成了组件数据绑定到AppStorage中,单向绑定且是一对多;而绑定的数值由第一个建立绑定的组件确定,然后只有改变AppStorage的数值才可以通知所有实例组件发生改变。
LocalStorage
**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组件进行状态更新。
PersistentStorage
PersistentStorage提供了一些静态方法用来管理应用持久化数据,可以将特定标记的持久化数据链接到AppStorage中,并由AppStorage接口访问对应持久化数据,或者通过@StorageLink装饰器来访问对应key的变量。
Environment
Environment是框架在应用程序启动时创建的单例对象,它为AppStorage提供了一系列应用程序需要的环境状态数据,这些数据描述了应用程序运行的设备环境,包括系统语言、深浅色模式等等。Environment及其属性是不可变的,所有数据类型均为简单类型。
动态构建UI元素
@Builder
这里我的理解是类似于封装函数并以供反复调用,组件内有结构且内容相似的地方都可以尝试封装成函数用@Builder反复调用。
例如:自定义文本框,自定义按钮,自定义tabbar等等
@BuilderParam
在初始化组件的时候,将@Builder装饰的函数传入并赋值给@BuilderParam修饰的属性,然后在组件内调用
尾随闭包初始化组件
在自定义组件中使用@BuilderParam修饰的属性时也可通过尾随闭包进行初始化(在初始化自定义组件时,组件后紧跟一个大括号“{}”形成尾随闭包场景(
CustomContainer(){}
)。开发者可把尾随闭包看做一个容器,向其中填充内容,如在闭包内增加组件({Column(){...}
),闭包内语法规范与build函数一致。此场景下自定义组件内有且仅有一个使用@BuilderParam修饰的属性。
@Styles
通过@Styles装饰器可以把统一的样式代码封装成一个函数,方便于多次调用相同样式代码,精简代码以及减少高质量,降低代码维护难度;但是,目前@Styles仅支持通用属性,并不是很好用。另外,@Styles还可以在StateStyles属性内部使用,在组件处于不同的状态时赋予相应的属性
@Extend
@Extend装饰器将新的属性方法添加到Text、Column、Button等内置组件上,通过@Extend装饰器可以快速地扩展原生组件。@Extend不能定义在自定义组件struct内。
说明:
- @Extend装饰器不能定义在自定义组件struct内。
- @Extend装饰器内仅支持属性方法设置。
@CustomDialog
@CustomDialog装饰器用于装饰自定义弹窗组件,使得弹窗可以动态设置内容及样式。
渲染控制
条件渲染
使用if/else进行条件渲染,当条件满足的时候才会将对应内容渲染出来。这里注意的是,每次改变条件触发渲染的时候,它都是从零渲染,不会预渲染,和显隐控制不同;对性能有严格要求时可以尽量使用条件渲染。
循环渲染
通过循环渲染(ForEach)从数组中获取数据,并为每个数据项创建相应的组件,可大幅度减少代码复杂度,更为简单地完成动态渲染的效果,只需要改变数据项目的内容,就可以完成增删改的动态渲染。
数据懒加载
通过数据懒加载(LazyForEach)从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。
说明:
- LazyForEach必须在容器组件内使用,目前仅有List、Grid以及Swiper组件支持数据懒加载(即只加载可视部分以及其前后少量数据用于缓冲),其他组件仍然是一次性加载所有的数据。
- LazyForEach在每次迭代中,必须创建且只允许创建一个子组件。
- 生成的子组件必须是允许包含在LazyForEach父容器组件中的子组件。
- 允许LazyForEach包含在if/else条件渲染语句中。
- 为了高性能渲染,通过DataChangeListener对象的onDataChange方法来更新UI时,仅当itemGenerator中创建的子组件内使用了状态变量时,才会触发组件刷新。
- itemGenerator函数的调用顺序不一定和数据源中的数据项相同,在开发过程中不要假设itemGenerator和keyGenerator函数是否执行及其执行顺序。
使用限制与扩展
在生成器函数中的使用限制
ArkTS语言的使用在生成器函数中存在一定的限制:
- 表达式仅允许在字符串(${expression})、if/else条件语句、ForEach的参数以及组件的参数中使用。
- 任何表达式都不能导致应用程序中状态变量(@State、@Link、@Prop)的改变,否则会造成未定义和潜在不稳定的框架行为。
- 生成器函数内部不能有局部变量。
上述限制都不适用于事件方法(如onClick)的匿名函数实现。
变量的双向绑定
用$$双向绑定变量,常用于状态频繁发生改变的变量,这样可以提高渲染速度。因为在被绑定的变量变化时,仅渲染刷新当前组件。
状态变量数据类型声明使用限制
1、所有的状态装饰器变量需要显式声明变量类型,不允许声明any,不支持Date数据类型。
2、@State、@Provide、 @Link和@Consume四种状态变量的数据类型声明只能由简单数据类型或引用数据类型的其中一种构成。
类型定义中的Length、ResourceStr、ResourceColor三个类型是简单数据类型或引用数据类型的组合,所以不能被以上四种状态装饰器变量使用。
自定义组件成员变量初始化的方式与约束
组件的成员变量可以通过两种方式初始化:
@State counter: Counter = new Counter() // 本地初始化
MyComponent({counter: $myCounter}) // 在构造组件时通过构造参数初始化
装饰器类型 | 本地初始化 | 通过构造函数参数初始化 |
---|---|---|
@State | 必须 | 可选 |
@Prop | 禁止 | 必须 |
@Link | 禁止 | 必须 |
@StorageLink | 必须 | 禁止 |
@StorageProp | 必须 | 禁止 |
@LocalStorageLink | 必须 | 禁止 |
@LocalStorageProp | 必须 | 禁止 |
@Provide | 必须 | 可选 |
@Consume | 禁止 | 禁止 |
@ObjectLink | 禁止 | 必须 |
常规成员变量 | 推荐 | 可选 |