关键字
??
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个字节