关键字
??
data??''表示如果data是null或undefined否则返回右侧的''
?.
data?.表达式表示如果data对象为null或undefined,返回undefined,不会抛出异常【操作的是对象及其属性或方法;返回的是属性值或方法返回值,如果对象不存在则返回undefined;用于安全访问】
?:
表达式?:表达式【操作的是条件和表达式;返回的是满足条件的表达式;用于条件判断】
=> (又名Lambda函数)
${变量} 字符串模版字面量
Promise
异步并发概述 (Promise和async/await)
Promise有三种状态:pending(进行中)、fulfilled(已完成)、rejected(已拒绝)。Promise对象创建后处于pending状态,并在异步操作完成后转换为fulfilled或rejected状态。  
单次I/O任务开发指导
async
await
let 定义变量
const 定义常量
concat
把指定字符串拼接到前面字符串的最后
UI范式基本语法
@Builder
- 组件内的
@Builder方法可通过this访问当前组件的属性和方法,而全局的@Builder方法则不能 - 组件内的
@Builder方法只能用于当前组件,全局的@Builder方法导出(export)后,可用于整个应用。 @Builder方法具有两种参数传递机制——按值传递和按引用传递。当只有一个参数且参数为对象字面量时为按引用传递,其余情况均为按值传递。
按引用传递时,若传递的参数为状态变量,则状态变量的变化将会触发@Builder方法内部UI的刷新;按值传递时则不会。@Builder方法和自定义组件的区别@Builder方法和自定义组件虽然都可以实现UI复用的效果,但是两者还是有着本质的区别的,其中最为显著的一个区别就是自定义组件可以定义自己的状态变量,而@Builder方法则不能。[!总结] 若复用的UI结构没有状态,推荐使用
@Builder方法,否则使用自定义组件。@LocalBuilder装饰器: 维持组件父子关系
@BuilderParam装饰器:引用@Builder函数
wrapBuilder:封装全局@Builder
@Styles装饰器:定义组件重用样式
@Extend装饰器:定义扩展组件样式
stateStyles:多态样式
@AnimatableExtend装饰器:定义可动画属性
@Require
校验
@Prop、@State、@Provide、@BuilderParam和普通变量(无状态装饰器修饰的变量)是否需要构造传参的一个装饰器。
添加了@Require就是必传的参数,不传编译不通过。@Reusable装饰器:组件复用
状态管理V1
管理组件拥有的状态
@Component自定义组件
@BuilderParam用于装饰自定义组件(struct)中的属性,其装饰的属性可作为一个UI结构的==占位符==,待创建该组件时,可通过参数为其传入具体的内容。(其作用类似于Vue框架中的slot)。- 一个组件中只定义了一个
@BuilderParam属性,那么创建该组件时,也可直接通过”子组件“(可用@Builder构建的组件当子组件)的方式传入具体的UI结构 
@State装饰器:组件内状态
@State装饰的变量,或称为状态变量,一旦变量拥有了状态属性,就和自定义组件的渲染绑定起来。当状态改变时,UI会发生对应的渲染改变。
在状态变量相关装饰器中,@State是最基础的,使变量拥有状态属性的装饰器,它也是大部分状态变量的数据源。
@State装饰的变量,与声明式范式中的其他被装饰变量一样,是私有的,只能从组件内部访问,在声明时必须指定其类型和本地初始化。初始化也可选择使用命名参数机制从父组件完成初始化。
@State装饰的变量拥有以下特点:  
@State装饰的变量与子组件中的@Prop装饰变量之间建立单向数据同步,与@Link、@ObjectLink装饰变量之间建立双向数据同步@State装饰的变量生命周期与其所属自定义组件的生命周期相同
本质是通过回调。
每个被@State修饰的变量最终都会被编译成一个ObservedPropertyObjectPU类的实现(/state_mgmt/src/lib/common/ObservedPropertyObjectPU是继承了ObservedPropertyPU的一个实现,前者的所有set/get方法都会调用后者的set/get方法)。
ArkTS在TS基础上把我们用状态修饰器修饰的变量进行了封装,内部通过ObservedPropertyPU类中set/get来更新值
1  | ObservedPropertyPU 类中  | 
这里面实际主要做了以下三件事:
- 进行内部状态值更新,并设置回调。【
 setValueInternal里面会把wrappedValue_更新为最后一次set的值】- 绑定回调方,比如当属性发生通知的时候,通过回调告诉回调方。【绑定回调方。这里先通过
 this.unsubscribeWrappedObject();把旧的值解除绑定。这里面判断了是SubscribableAbstract还是ObservedObject进行单独的处理。】
1  | private unsubscribeWrappedObject() {  | 
- 把UI设置为脏处理,应用于后面UI的刷新流程。【
 setValueInternal返回true的时候,就会执行notifyObjectValueAssignment进行回调,最终分为两个分支:如果class里面没有@Track装饰器修饰的变量,则通过notifyPropertyHasChangedPU方法进行刷新(所有依赖这个class的UI都会被刷新),如果有的话,则通过notifyTrackedObjectPropertyHasChanged进行刷新(只依赖@Track装饰器修饰的变量的UI才会刷新)。】
1  | if (this.setValueInternal(newValue)) {  | 
@Prop装饰器:父子单向同步
@Prop装饰的变量可以和父组件建立单向的同步关系。@Prop装饰的变量是可变的,但是变化不会同步回其父组件。@Prop自带@State效果,即更改@Prop修饰的变量会更新UI【子组件的aboutToApear()在创建时自动触发】@Prop装饰的变量和父组件建立单向的同步关系:  
@Prop变量允许在本地修改,但修改后的变化不会同步回父组件。- 当父组件中的数据源更改时,与之相关的
@Prop装饰的变量都会自动更新。如果子组件已经在本地修改了@Prop装饰的相关变量值,而在父组件中对应的@State装饰的变量被修改后,子组件本地修改的@Prop装饰的相关变量值将被覆盖。
子组件中被@Link装饰器:父子双向同步@Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。@Link装饰的变量与其父组件中的数据源共享相同的值。@Link装饰器不能在@Entry装饰的自定义组件中使用。@Provide装饰器/@Consume装饰器@Provide和@Consume,应用于与后代组件的双向数据同步,应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递,@Provide和@Consume摆脱参数传递机制的束缚,实现跨层级传递。
其中@Provide装饰的变量是在祖先节点中,可以理解为被“提供”给后代的状态变量。@Consume装饰的变量是在后代组件中,去“消费(绑定)”祖先节点提供的变量。@Provide/@Consume装饰的状态变量有以下特性: @Provide装饰的状态变量自动对其所有后代组件可用,即该变量被“provide”给他的后代组件。由此可见,@Provide的方便之处在于,开发者不需要多次在组件之间传递变量。- 后代通过使用
@Consume去获取@Provide提供的变量,建立在@Provide和@Consume之间的双向数据同步,与@State/@Link不同的是,前者可以在多层级的父子组件之间传递。 @Provide和@Consume可以通过相同的变量名或者相同的变量别名绑定,变量类型必须相同。1
2
3
4
5
6
7// 通过相同的变量名绑定
a: number = 0;
a: number;
// 通过相同的变量别名绑定
('a') b: number = 0;
('a') c: number;@Provide和@Consume通过相同的变量名或者相同的变量别名绑定时,@Provide修饰的变量和@Consume修饰的变量是一对多的关系。不允许在同一个自定义组件内,包括其子组件中声明多个同名或者同别名的@Provide装饰的变量。[!tip]
@Provide可以和@Watch一起用,和其他状态变量不能一起用(编译报错)@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化
@Observed和@ObjectLink嵌套对象属性更改UI不刷新问题
使用了
@Observed和@ObjectLink,修改嵌套对象的属性,UI还是不刷新,常见问题有三种形式:
- 多级嵌套,嵌套对象的类并没有添加
@Observed进行监听 - 多级嵌套,嵌套对象的 
View组件没有抽离出来,添加@ObjectLink进行该级对象的监听绑定 - 嵌套对象,并没有
new出来创建,直接赋值没有创建对象的过程,无法激活Observed监听管理应用拥有的状态
@AppStorage@AppStorage应用全局的UI状态存储
应用全局的UI状态存储,和应用进程绑定。是“中枢”,持久化数据PersistentStorage和环境变量Environment都是通过它来中转,才可与UI交互。【单例、它的所有API都是静态的】 
- 修饰器
@StorageProp单向数据同步,AppStorage改变可同步给@StorageProp并覆盖本地的修改
 - 修饰器
@StorageLink双向数据同步
@StorageProp
@StorageLink
 
LocalStorage 页面级UI状态存储
@LocalStorageProp
@LocalStorageLink
PersistentStorage:持久化存储UI状态
Environment:设备环境查询
其他状态管理
@Watch
状态变量更改通知。(===)严格相等为false时触发@Watch的回调
    1. 当观察到状态变量的变化(包括双向绑定的AppStorage和LocalStorage中对应的key发生的变化)的时候,对应的@Watch的回调方法将被触发;
    2. @Watch方法在自定义组件的属性变更之后同步执行;
    3. 如果在@Watch的方法里改变了其他的状态变量,也会引起状态变更和@Watch的执行;
    4. 在第一次初始化的时候,@Watch装饰的方法不会被调用,即认为初始化不是状态变量的改变。只有在后续状态改变时,才会调用@Watch回调方法。
$$语法:内置组件双向同步
$$绑定的变量变化时,会触发UI的同步刷新。
| 组件 | 支持的参数/属性 | 起始API版本 | 
|---|---|---|
| Checkbox提供多选框组件 | select | 10 | 
| CheckboxGroup | selectAll | 10 | 
| DatePicker日期选择器组件 | selected | 10 | 
| TimePicker时间选择器组件 | selected | 10 | 
| MenuItem展示菜单Menu中具体的item菜单项 | selected | 10 | 
| Panel可滑动面板【停止维护】 | mode | 10 | 
| Radio单选框 | checked | 10 | 
| Rating评分组件 | rating | 10 | 
| Search搜索框组件 | value | 10 | 
| SideBarContainer可以显示和隐藏的侧边栏容器 | showSideBar | 10 | 
| Slider滑动条组件 | value | 10 | 
| Stepper步骤导航器组件 | index | 10 | 
| Swiper滑块视图容器,提供子组件滑动轮播显示的能力 | index | 10 | 
| Tabs通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图 | index | 10 | 
| TextArea多行文本输入框组件,可自动换行 | text | 10 | 
| TextInput单行文本输入框组件 | text | 10 | 
| TextPicker滑动选择文本内容的组件 | selected、value | 10 | 
| Toggle组件提供勾选框样式、状态按钮样式及开关样式。 | isOn | 10 | 
| AlphabetIndexer可以与容器组件联动用于按逻辑结构快速定位容器显示区域的组件 | selected | 10 | 
| Select提供下拉选择菜单,可以让用户在多个选项之间选择。 | selected、value | 10 | 
| BindSheet半模态转场 | isShow | 10 | 
| BindContentCover# 全屏模态转场 | isShow | 10 | 
| Refresh页面下拉操作并显示刷新动效的容器组件 | refreshing | 8 | 
| GridItem网格容器中单项内容容器 | selected | 10 | 
| ListItem展示列表具体item,必须配合List来使用 | selected | 10 | 
@Track装饰器:class对象属性级更新
应用于==class对象==的属性级更新。装饰的属性变化时,只会触发该属性关联的UI更新。
| @Track变量装饰器 | 说明 | 
|---|---|
| 装饰器参数 | 无 | 
| 可装饰的变量 | class对象的非静态成员属性。 | 
自定义组件冻结功能
状态管理V2
@ComponentV2自定义组件
@ObservedV2装饰器和@Trace装饰器:类属性变化观测
@Local
对@ComponentV2装饰的自定义组件中变量变化的观测,开发者可以使用@Local装饰器装饰变量。  
- 被
@Local装饰的变量无法从外部初始化,因此必须在组件内部进行初始化。 - 当被
@Local装饰的变量变化时,会刷新使用该变量的组件。 @Local支持观测number、boolean、string、Object、class等基本类型以及Array、Set、Map、Date等内嵌类型。@Local的观测能力仅限于被装饰的变量本身。当装饰简单类型时,能够观测到对变量的赋值;当装饰对象类型时,仅能观测到对对象==整体==的赋值;当装饰数组类型时,能观测到数组==整体==以及==数组元素项==的变化;当装饰Array、Set、Map、Date等内嵌类型时,可以观测到通过API调用带来的变化。详见观察变化。@Local支持null、undefined以及联合类型。@Param:组件外部输入
@Once:初始化同步一次
@Event装饰器:规范组件输出
@Provider装饰器和@Consumer装饰器:跨组件层级双向同步
@Monitor装饰器:状态变量修改监听
@Computed装饰器:计算属性
@Type装饰器:标记类属性的类型
router
页面路由 (@ohos.router)(不推荐)
Router模块通过不同的url地址,可以方便地进行页面路由。 
页面跳转【页面栈的最大容量为32个页面】
- router.pushUrl():目标页面不会替换当前页,而是压入页面栈。这样可以保留当前页的状态,并且可以通过返回键或者调用router.back()方法返回到当前页。
 - router.replaceUrl():目标页面会替换当前页,并销毁当前页。这样可以释放当前页的资源,并且无法返回到当前页。
 - router.clear()方法清空历史页面栈
 - 两种实例模式,分别是Standard【默认】和Single
- Standard:多实例模式【默认】。目标页面会被添加到页面**==栈==顶**,无论栈中是否存在相同url的页面。
 - Single:单实例模式。如果目标页面的url已经存在于页面栈中,则会将离栈顶最近的同url页面移动到栈顶【没有清空栈中该url以上的其他页面】,该页面成为新建页。如果目标页面的url在页面栈中不存在同url页面,则按照默认的多实例模式进行跳转。
 
 
- 
- 使用
router.back()方法返回到指定页面时,原栈顶页面(包括)到指定页面(不包括)之间的所有页面栈都将从栈中弹出并销毁。 - 使用
router.back()方法返回到原来的页面,原页面不会被重复创建,因此使用@State声明的变量不会重复声明,也不会触发页面的aboutToAppear()生命周期回调。如果需要在原页面中使用返回页面传递的自定义参数,可以在需要的位置进行参数解析。例如,在onPageShow()生命周期回调中进行参数解析。 
 - 使用
 - 
- 跳转到共享包Har或者Hsp中的页面(即共享包中路由跳转),可以使用router.pushNamedRoute()来实现
- 给共享包的目标页面加别名 
@Entry({routeName:'myPage'}) - 当前包
oh-package.json5的dependencies中加"@ohos/library":"file:../library" - 当前包的当前页面加导入
1. import '@ohos/library/src/main/ets/pages/Index'; // 引入共享包中的命名路由页面 - 当前页面跳转使用 
router.pushNamedRoute({ name: 'myPage', params:...})navigation
navigation
navigation13
Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(Navigation的子组件)或非首页显示(NavDestination13的子组件),首页和非首页通过路由进行切换。
组件导航 (Navigation)(推荐)
从API Version 9开始,推荐与 NavRouter 组件搭配使用。
从API Version 10开始,推荐使用 NavPathStack 【路由栈信息】配合 NavDestination【NavRouter组件的子组件,用于显示导航内容区】属性进行页面路由。
title:使用NavigationCustomTitle类型设置height高度时,titleMode属性不会生效。
… 
 - 给共享包的目标页面加别名 
 
 - 跳转到共享包Har或者Hsp中的页面(即共享包中路由跳转),可以使用router.pushNamedRoute()来实现
 通用属性
width、height、size【SizeOptions对象】、padding、margin、layoutWeight、constraintSize【ConstraintSizeOptions对象】[!说明]
- 非全屏窗口下,Navigation/NavDestination设置的状态栏不生效
 
navigation加属性
.mode(NavigationMode.Stack),Navigation组件即可设置为单页面显示模式。【默认为自适应模式】.mode(NavigationMode.Split),Navigation组件即可设置为分栏显示模式。navigation路由相关操作(页面跳转、页面返回、页面替换、页面删除、参数获取、路由拦截等)都是基于页面栈 NavPathStack 提供的方法进行。每个Navigation都需要创建并传入一个NavPathStack对象。
API version12开始,页面栈允许被继承。页面栈继承示例代码。
pushPathByName:
除了支持通用属性外,Navigation 还支持以下属性:
title:设置页面标题。从 API version 11 开始,该接口支持在元服务中使用。subTitle(deprecated):设置页面副标题。从 API Version 9 开始废弃,建议使用 title 代替。menus:设置导航栏菜单项。titleMode:设置标题栏模式。toolBar(deprecated):设置工具栏。从 API Version 10 开始废弃,建议使用 toolbarConfiguration 代替。toolbarConfiguration:设置工具栏配置。hideToolBar:设置是否隐藏工具栏。hideTitleBar:设置是否隐藏标题栏。hideBackButton:设置是否隐藏返回按钮。navBarWidth:设置导航栏宽度。navBarPosition:设置导航栏位置。mode:设置导航模式。backButtonIcon:设置返回按钮图标。hideNavBar:设置是否隐藏导航栏。navDestination:设置导航目的地。navBarWidthRange:设置导航栏宽度范围。minContentWidth:设置内容区最小宽度。ignoreLayoutSafeArea:设置是否忽略布局安全区域。systemBarStyle:设置系统状态栏样式。事件
onTitleModeChange:标题栏模式改变事件。onNavBarStateChange:导航栏状态改变事件。onNavigationModeChange:导航模式改变事件。customNavContentTransition:自定义导航内容过渡动画。相关类型
NavPathStack:路由栈信息。NavPathInfo:路由路径信息。PopInfo:弹出信息。NavContentInfo:导航内容信息。NavigationAnimatedTransition:导航动画过渡。NavigationTransitionProxy:导航过渡代理。NavigationInterception:导航拦截。InterceptionShowCallback:导航显示拦截回调。InterceptionModeCallback:导航模式拦截回调。NavBar:导航栏。NavigationMenuItem:导航菜单项。ToolbarItem:工具栏项。ToolbarItemStatus:工具栏项状态。枚举说明
NavigationTitleMode:标题栏模式。NavigationCommonTitle:普通标题。NavigationCustomTitle:自定义标题。NavBarPosition:导航栏位置。NavigationMode:导航模式。TitleHeight:标题栏高度。NavigationOperation:导航操作。BarStyle:状态栏样式。NavigationTitleOptions:标题栏选项。NavigationToolbarOptions:工具栏选项。LaunchMode:启动模式。NavigationOptions:导航选项。
Preference
key为string非空长度超过1024个字节