编程语言介绍
ArkUI开发语言是ArkTs,也是目前的HarmonyOS的主力开发语言。是的,没有看错,之前选择的java开发语言已经被扫进了历史的垃圾堆,遥遥领先的某司选择了更贴近前端的语言。本客户端仔再一次感受到恶意。
ArkTS,是“遥遥领先”在TS生态基础上做的进一步扩展,可以理解为是ts的一个超集。它继承了TS的所有特性,并且扩展了如下的能力:
-
基础语法:ArkTS定义了声明式UI描述、自定义组件和动态扩展UI元素的能力,再配合ArkUI开发框架中的系统组件及其相关的事件方法、属性方法等共同构成了UI开发的主体。
-
状态管理:ArkTS提供了多维度的状态管理机制。在UI开发框架中,与UI相关联的数据可以在组件内使用,也可以在不同组件层级间传递,比如父子组件之间、爷孙组件之间,还可以在应用全局范围内传递或跨设备传递。另外,从数据的传递形式来看,可分为只读的单向传递和可变更的双向传递。开发者可以灵活地利用这些能力来实现数据和UI的联动。
-
渲染控制:ArkTS提供了渲染控制的能力。条件渲染可根据应用的不同状态,渲染对应状态下的UI内容。循环渲染可从数据源中迭代获取数据,并在每次迭代过程中创建相应的组件。数据懒加载从数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。
基础构成
接下来详细讲讲ArkUI基础组成,区别于传统的前端js html css三剑客的写法。ArkTs更类似于 Fluter 和 安卓的Compose。
本示例中可以看到ArkUI组成如下
装饰器
ArkTs 提供了一系列类似注解的装饰器,它用来给变量赋予特殊的含义。
@Component:表示自定义组件。使用场景是在我们需要组合原生控件,或者想做自己需要的效果的控件的时候。
@Entry: 表示自定义组件的入口,一般用于页面级的组件,一个UI页面中只能有一个此装饰器。
@State: 表示组件中的状态变量,被修饰的状态变量被UI描述使用时,修改变量会改变UI的展示。
UI描述
build()中和代码块即UI描述,这里就是我辈UI仔画界面的地方。此处可以堆砌各种系统组件。组件的属性方法与事件方法。这些可以通过链式方法调用。
ArtUI框架提供相当丰富的组件供开发者使用 参考文档
此外还提供了相当多的布局组件供开发者使用 参考文档
常见的容器组件
Column
沿垂直方向布局的容器。
// xxx.ets
@Entry
@Component
struct ColumnExample {
build() {
Column({ space: 5 }) {
// 设置子元素垂直方向间距为5
Text('space').width('90%')
Column({ space: 5 }) {
Column().width('100%').height(30).backgroundColor(0xAFEEEE)
Column().width('100%').height(30).backgroundColor(0x00FFFF)
}.width('90%').height(100).border({ width: 1 })
// 设置子元素水平方向对齐方式
Text('alignItems(Start)').width('90%')
Column() {
Column().width('50%').height(30).backgroundColor(0xAFEEEE)
Column().width('50%').height(30).backgroundColor(0x00FFFF)
}.alignItems(HorizontalAlign.Start).width('90%').border({ width: 1 })
Text('alignItems(End)').width('90%')
Column() {
Column().width('50%').height(30).backgroundColor(0xAFEEEE)
Column().width('50%').height(30).backgroundColor(0x00FFFF)
}.alignItems(HorizontalAlign.End).width('90%').border({ width: 1 })
Text('alignItems(Center)').width('90%')
Column() {
Column().width('50%').height(30).backgroundColor(0xAFEEEE)
Column().width('50%').height(30).backgroundColor(0x00FFFF)
}.alignItems(HorizontalAlign.Center).width('90%').border({ width: 1 })
// 设置子元素垂直方向的对齐方式
Text('justifyContent(Center)').width('90%')
Column() {
Column().width('90%').height(30).backgroundColor(0xAFEEEE)
Column().width('90%').height(30).backgroundColor(0x00FFFF)
}.height(100).border({ width: 1 }).justifyContent(FlexAlign.Center)
Text('justifyContent(End)').width('90%')
Column() {
Column().width('90%').height(30).backgroundColor(0xAFEEEE)
Column().width('90%').height(30).backgroundColor(0x00FFFF)
}.height(100).border({ width: 1 }).justifyContent(FlexAlign.End)
}.width('100%').padding({ top: 5 })
}
}
Row
沿着水平方向的容器布局
// xxx.ets
@Entry
@Component
struct RowExample {
build() {
Column({ space: 5 }) {
// 设置子组件水平方向的间距为5
Text('space').width('90%')
Row({ space: 5 }) {
Row().width('30%').height(50).backgroundColor(0xAFEEEE)
Row().width('30%').height(50).backgroundColor(0x00FFFF)
}.width('90%').height(107).border({ width: 1 })
// 设置子元素垂直方向对齐方式
Text('alignItems(Bottom)').width('90%')
Row() {
Row().width('30%').height(50).backgroundColor(0xAFEEEE)
Row().width('30%').height(50).backgroundColor(0x00FFFF)
}.width('90%').alignItems(VerticalAlign.Bottom).height('15%').border({ width: 1 })
Text('alignItems(Center)').width('90%')
Row() {
Row().width('30%').height(50).backgroundColor(0xAFEEEE)
Row().width('30%').height(50).backgroundColor(0x00FFFF)
}.width('90%').alignItems(VerticalAlign.Center).height('15%').border({ width: 1 })
// 设置子元素水平方向对齐方式
Text('justifyContent(End)').width('90%')
Row() {
Row().width('30%').height(50).backgroundColor(0xAFEEEE)
Row().width('30%').height(50).backgroundColor(0x00FFFF)
}.width('90%').border({ width: 1 }).justifyContent(FlexAlign.End)
Text('justifyContent(Center)').width('90%')
Row() {
Row().width('30%').height(50).backgroundColor(0xAFEEEE)
Row().width('30%').height(50).backgroundColor(0x00FFFF)
}.width('90%').border({ width: 1 }).justifyContent(FlexAlign.Center)
}.width('100%')
}
}
Stack
堆叠布局
// xxx.ets
@Entry
@Component
struct StackExample {
build() {
Stack({ alignContent: Alignment.Bottom }) {
Text('First child, show in bottom').width('90%').height('100%').backgroundColor(0xd2cab3).align(Alignment.Top)
Text('Second child, show in top').width('70%').height('60%').backgroundColor(0xc1cbac).align(Alignment.Top)
}.width('100%').height(150).margin({ top: 5 })
}
}
自定义组件
在ArkUI中,UI显示的内容均为组件,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。这里和安卓很像,就是安卓中的自定义控件。但与安卓的自定义控件相比,使用ArkUI范式写出来的自定义组件就多了响应式UI数据驱动更新这一特点。
自定义组件的基本结构
一个最小化的自定义组件包含 struct关键字 + @Component修饰器 + build()函数
@Component
struct MyComponent {
build() {
}
}
这样就是一个最最最简单的的空组件
当然一个空的组件是没有什么用的。必然还需要UI 数据 逻辑。
UI
UI上面我们说了是在build()中增加UI描述即可。当然这里面也有一些相关的约束
- 仅Component修饰的组件,根结点唯一且必要,可以是非容器组件
- 被Entry修饰的组件则,根结点唯一且必要,并且必须是容器组件
- 不允许在build里申明变量数据
- 不允许在build中打印日志
- 不允许创建本地作用域
build() {
// 反例:不允许本地作用域
{
...
}
}
- 不允许调用没有被Builder修饰的方法的,但允许在组件参数中使用此类方法
@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语法
- 也不允许使用表达式
数据与逻辑
一个组件当然不只是UI,还有数据与逻辑即,成员函数和变量数据。在ArkUI中这些东西也存在一些约束。
成员函数约束:
- 不支持静态函数。
- 成员函数的访问为私有,对外不能访问
成员变量约束
- 不支持静态函数,自然也就不会支持静态变量
- 所有成员变量也是私有
- 自定义组件的成员变量本地初始化有些是可选的,有些是必选的。