鸿蒙应用开发从入门到实战(四):ArkTS 语言概述

大家好,我是潘 Sir,持续分享 IT 技术,帮你少走弯路。《鸿蒙应用开发从入门到项目实战》系列文章持续更新中,欢迎关注!
一、HarmonyOS 开发语言 ArkTS 概述
HarmonyOS 应用的主要开发语言是 ArkTS,它由 TypeScript(简称 TS)扩展而来,在继承 TypeScript 语法的基础上进行了一系列优化,使开发者能够以更简洁、更自然的方式开发应用。值得注意的是,TypeScript 本身也是由另一门语言 JavaScript 扩展而来。因此三者的关系如下图所示

ArkTS 是 HarmonyOS 优选的主力应用开发语言。ArkTS 围绕应用开发在 TypeScript(简称 TS)生态基础上做了进一步扩展,继承了 TS 的所有特性,是 TS 的超集。
因此,在学习 ArkTS 语言之前,建议开发者具备 TS 语言开发能力。
当前,ArkTS 在 TS 的基础上主要扩展了如下能力:
基本语法
ArkTS 定义了声明式 UI 描述、自定义组件和动态扩展 UI 元素的能力,再配合 ArkUI 开发框架中的系统组件及其相关的事件方法、属性方法等共同构成了 UI 开发的主体。
状态管理
ArkTS 提供了多维度的状态管理机制。在 UI 开发框架中,与 UI 相关联的数据可以在组件内使用,也可以在不同组件层级间传递,比如父子组件之间、爷孙组件之间,还可以在应用全局范围内传递或跨设备传递。另外,从数据的传递形式来看,可分为只读的单向传递和可变更的双向传递。开发者可以灵活地利用这些能力来实现数据和 UI 的联动。
渲染控制
ArkTS 提供了渲染控制的能力。条件渲染可根据应用的不同状态,渲染对应状态下的 UI 内容。循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件。数据懒加载从数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。
未来,ArkTS 会结合应用开发/运行的需求持续演进,逐步提供并行和并发能力增强、系统类型增强、分布式开发范式等更多特性。
二、ArkTS 基本语法
2.1 基本语法概述
在初步了解了 ArkTS 语言之后,我们以一个具体的示例来说明 ArkTS 的基本组成。如下图所示,当开发者点击按钮时,文本内容从“Hello World”变为“Hello ArkUI”。

本示例中,ArkTS 的基本组成如下所示

自定义变量不能与基础通用属性/事件名重复。
装饰器
用于装饰类、结构、方法以及变量,并赋予其特殊的含义。如上述示例中 @Entry、@Component 和 @State 都是装饰器,@Component 表示自定义组件,@Entry 表示该自定义组件为入口组件,@State 表示组件中的状态变量,状态变量变化会触发 UI 刷新。
UI 描述
以声明式的方式来描述 UI 的结构,例如 build()方法中的代码块。
自定义组件
可复用的 UI 单元,可组合其他组件,如上述被 @Component 装饰的 struct Hello。
系统组件
ArkUI 框架中默认内置的基础和容器组件,可直接被开发者调用,比如示例中的 Column、Text、Divider、Button。
属性方法
组件可以通过链式调用配置多项属性,如 fontSize()、width()、height()、backgroundColor()等。
事件方法
组件可以通过链式调用设置多个事件的响应逻辑,如跟随在 Button 后面的 onClick()。
除此之外,ArkTS 扩展了多种语法范式来使开发更加便捷:
@Builder/@BuilderParam
特殊的封装 UI 描述的方法,细粒度的封装和复用 UI 描述。
@Extend/@Styles
扩展内置组件和封装属性样式,更灵活地组合内置组件。
stateStyles
多态样式,可以依据组件的内部状态的不同,设置不同样式。
2.2 声明式 UI 描述
ArkTS 以声明方式组合和扩展组件来描述应用程序的 UI,同时还提供了基本的属性、事件和子组件配置方法,帮助开发者实现应用交互逻辑。
2.2.1 创建组件
根据组件构造方法的不同,创建组件包含有参数和无参数两种方式。
创建组件时不需要 new 运算符。
无参数
如果组件的接口定义没有包含必选构造参数,则组件后面的“()”不需要配置任何内容。例如,Divider 组件不包含构造参数:
有参数
如果组件的接口定义包含构造参数,则在组件后面的“()”配置相应参数。
(1)Image 组件的必选参数 src。
(2)Text 组件的非必选参数 content。
(3)变量或表达式也可以用于参数赋值,其中表达式返回的结果类型必须满足参数类型要求。
例如,设置变量或表达式来构造 Image 和 Text 组件的参数。
2.2.2 配置属性
属性方法以“.”链式调用的方式配置系统组件的样式和其他属性,建议每个属性方法单独写一行。
(1)配置 Text 组件的字体大小。
(2)配置组件的多个属性。
(3)除了直接传递常量参数外,还可以传递变量或表达式。
(4)对于系统组件,ArkUI 还为其属性预定义了一些枚举类型供开发者调用,枚举类型可以作为参数传递,但必须满足参数类型要求。
例如,可以按以下方式配置 Text 组件的颜色和字体样式。
2.2.3 配置事件
事件方法以“.”链式调用的方式配置系统组件支持的事件,建议每个事件方法单独写一行。
(1)使用箭头函数配置组件的事件方法。
(2)使用匿名函数表达式配置组件的事件方法,要求使用 bind,以确保函数体中的 this 指向当前组件。
(3)使用组件的成员函数配置组件的事件方法。
(4)使用声明的箭头函数,可以直接调用,不需要 bind this。
2.2.4 配置子组件
如果组件支持子组件配置,则需在尾随闭包"{...}"中为组件添加子组件的 UI 描述。Column、Row、Stack、Grid、List 等组件都是容器组件。
(1)以下是简单的 Column 组件配置子组件的示例。
(2)容器组件均支持子组件配置,可以实现相对复杂的多级嵌套。
基本语法中的自定义组件和扩展 UI 的能力在后续进行介绍。
三、ArkTS 状态管理
3.1 状态管理概述
在前文的描述中,我们构建的页面多为静态界面。如果希望构建一个动态的、有交互的界面,就需要引入“状态”的概念。
在上面的示例中,用户与应用程序的交互触发了文本状态变更,状态变更引起了 UI 渲染,UI 从“Hello World”变更为“Hello ArkUI”。
在声明式 UI 编程框架中,UI 是程序状态的运行结果,用户构建了一个 UI 模型,其中应用的运行时的状态是参数。当参数改变时,UI 作为返回结果,也将进行对应的改变。这些运行时的状态变化所带来的 UI 的重新渲染,在 ArkUI 中统称为状态管理机制。
自定义组件拥有变量,变量必须被装饰器装饰才可以成为状态变量,状态变量的改变会引起 UI 的渲染刷新。如果不使用状态变量,UI 只能在初始化时渲染,后续将不会再刷新。 下图展示了 State 和 View(UI)之间的关系。

View(UI):UI 渲染,指将 build 方法内的 UI 描述和 @Builder 装饰的方法内的 UI 描述映射到界面。
State:状态,指驱动 UI 更新的数据。用户通过触发组件的事件方法,改变状态数据。状态数据的改变,引起 UI 的重新渲染。
3.1.1 基本概念
状态变量:被状态装饰器装饰的变量,状态变量值的改变会引起 UI 的渲染更新。示例:@State num: number = 1,其中,@State 是状态装饰器,num 是状态变量。
常规变量:没有被状态装饰器装饰的变量,通常应用于辅助计算。它的改变永远不会引起 UI 的刷新。以下示例中 increaseBy 变量为常规变量。
数据源/同步源:状态变量的原始来源,可以同步给不同的状态数据。通常意义为父组件传给子组件的数据。以下示例中数据源为 count: 1。
命名参数机制:父组件通过指定参数传递给子组件的状态变量,为父子传递同步参数的主要手段。示例:CompA: ({ aProp: this.aProp })。
从父组件初始化:父组件使用命名参数机制,将指定参数传递给子组件。子组件初始化的默认值在有父组件传值的情况下,会被覆盖。示例:
初始化子节点:父组件中状态变量可以传递给子组件,初始化子组件对应的状态变量。示例同上。
本地初始化:在变量声明的时候赋值,作为变量的默认值。示例:@State count: number = 0。
3.1.2 装饰器总览
ArkUI 提供了多种装饰器,通过使用这些装饰器,状态变量不仅可以观察在组件内的改变,还可以在不同组件层级间传递,比如父子组件、跨组件层级,也可以观察全局范围内的变化。根据状态变量的影响范围,将所有的装饰器可以大致分为:
管理组件拥有状态的装饰器:组件级别的状态管理,可以观察组件内变化,和不同组件层级的变化,但需要唯一观察同一个组件树上,即同一个页面内。
管理应用拥有状态的装饰器:应用级别的状态管理,可以观察不同页面,甚至不同 UIAbility 的状态变化,是应用内全局的状态管理。
从数据的传递形式和同步类型层面看,装饰器也可分为:
只读的单向传递;
可变更的双向传递。
ArkUI 提供的装饰器如下图,开发者可以灵活地利用这些能力来实现数据和 UI 的联动。

上图中,Components 部分的装饰器为组件级别的状态管理,Application 部分为应用的状态管理。开发者可以通过 @StorageLink/@LocalStorageLink 实现应用和组件状态的双向同步,通过 @StorageProp/@LocalStorageProp 实现应用和组件状态的单向同步。
(1)管理组件拥有的状态 ,即图中 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 的实例,应用于观察多层嵌套场景,和父组件的数据源构建双向同步。
仅 @Observed/@ObjectLink 可以观察嵌套场景,其他的状态变量仅能观察第一层,详情见各个装饰器章节的“观察变化和行为表现”小节。
(2)管理应用拥有的状态,即图中 Application 级别的状态管理:
AppStorage 是应用程序中的一个特殊的单例 LocalStorage 对象,是应用级的数据库,和进程绑定,通过 @StorageProp 和 @StorageLink 装饰器可以和组件联动。
AppStorage 是应用状态的“中枢”,将需要与组件(UI)交互的数据存入 AppStorage,比如持久化数据 PersistentStorage 和环境变量 Environment。UI 再通过 AppStorage 提供的装饰器或者 API 接口,访问这些数据。
框架还提供了 LocalStorage,AppStorage 是 LocalStorage 特殊的单例。LocalStorage 是应用程序声明的应用状态的内存“数据库”,通常用于页面级的状态共享,通过 @LocalStorageProp 和 @LocalStorageLink 装饰器可以和 UI 联动。
(3)其他状态管理功能
除了前面提到的组件状态管理和应用状态管理,ArkTS 还提供了 @Watch 和 $$来为开发者提供更多功能:
@Watch 用于监听状态变量的变化。
$$运算符:给内置组件提供 TS 变量的引用,使得 TS 变量和内置组件的内部状态保持同步。
四、ArkTS 渲染控制
ArkUI 通过自定义组件的 build()函数和 @builder 装饰器中的声明式 UI 描述语句构建相应的 UI。在声明式描述语句中开发者除了使用系统组件外,还可以使用渲染控制语句来辅助 UI 的构建,这些渲染控制语句包括控制组件是否显示的条件渲染语句,基于数组数据快速生成组件的循环渲染语句以及针对大数据量场景的数据懒加载语句。
4.1 条件渲染
ArkTS 提供了渲染控制的能力。条件渲染可根据应用的不同状态,使用 if、else 和 else if 渲染对应状态下的 UI 内容。
4.2 循环渲染
ForEach 接口基于数组类型数据来进行循环渲染,需要与容器组件配合使用,且接口返回的组件应当是允许包含在 ForEach 父容器组件中的子组件。例如,ListItem 组件要求 ForEach 的父容器组件必须为 List 组件。
4.3 数据懒加载
LazyForEach 从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了 LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时,框架会进行组件销毁回收以降低内存占用。
《鸿蒙应用开发从入门到项目实战》系列文章持续更新中,欢迎关注!
版权声明: 本文为 InfoQ 作者【程序员潘Sir】的原创文章。
原文链接:【http://xie.infoq.cn/article/6016e472304b93fcb22111008】。文章转载请联系作者。
评论