共计 6576 个字符,预计需要花费 17 分钟才能阅读完成。
「鸿蒙」ArtTS 根底入门学习笔记
ArtTS 基础知识
ArtTS
ArkTS 是 HarmonyOS 优选的主力利用开发语言。它在 TypeScript(简称 TS)的根底上,扩大了申明式 UI、状态治理等相应的能力,让开发者能够以更简洁、更天然的形式开发高性能利用。TS 是 JavaScript(简称 JS)的超集,ArkTS 则是 TS 的超集。ArkTS 会联合利用开发和运行的需要继续演进,包含但不限于引入分布式开发范式、并行和并发能力加强、类型零碎加强等方面的语言个性。
基于 JS 的前端框架以及 TS 的引入,进一步晋升了利用开发效率,但仍然存在一些有余。
从开发者维度来看:
写一个利用须要理解三种语言(JS/TS、HTML 和 CSS)。这对 Web 开发者绝对敌对,但对非 Web 开发者来说,累赘较重。
从运行时维度来看:
- 在语言运行时方面,只管 TS 有了类型的加持,但也只是用于编译时查看,而后通过 TS Compiler 转成 JS,运行时引擎还是无奈利用到基于类型零碎的优化。
- 在渲染方面,支流 Web 引擎因为自身复杂度以及历史起因,性能、资源占用方面与常见 OS 原生框架都有肯定的差距,尤其在挪动平台上。React Native 通过渲染架构的改良肯定水平上晋升了性能体验,但在平台渲染成果和能力的一致性,以及 JS 语言性能等方面还是存在肯定的有余。
Google 在 2018 年底推出的 Flutter 则走了另外一条路,联合新的语言 Dart,引入新的申明式开发范式,基于 Skia 的自绘制引擎构建可跨平台的独立的渲染能力。这是一种较为翻新的计划,不过也有几点有余:
- Dart 语言生态。只管 Dart 语言 2011 年就已推出,风闻其指标是取代 JS,但整个生态还是十分强大,Dart 语言公布 7 年后随着 Flutter 的推出才有所改善。整体而言,Dart 和支流语言生态相比还是有十分大的差距。
- 开发范式。Flutter 裸露了很多细粒度的 Widget 接口,整体开发的简洁度,开发门槛,尤其是和 Apple 推出的 SwiftUI 相比,存在肯定的差距。
有意思的是,Google 在 2021 年又推出了新的开发框架 Jetpack Compose,联合了 Kotlin 的语言生态,设计了新的申明式 UI 开发范式。
2019 年,咱们在思考如何构建新的利用开发框架的时候,从以下几个维度进行了重点思考:
- 语言生态
- 开发效率
- 性能体验
- 跨设施 / 跨平台能力
因为 JS/TS 有比较完善的开发者生态,语言也比拟中立敌对,有相应的规范组织能够逐渐演进,JS/TS 语言成了比拟天然的抉择。以 JS/TS 为根底,在开发框架的维度,咱们做了如下的架构演进设计:
- 通过基于 JS 扩大的类 Web 开发范式,来反对支流的前端开发形式。同步的,在运行时方面,通过 渲染引擎的加强(平台无关的自绘制机制、申明式 UI 后端设计、动静布局 / 多态 UI 组件等),语言编译器和运行时的优化加强(代码预编译、高效 FFI-Foreign Function Interface、引擎极小化等),进一步 晋升相干的性能体验 ,并 可部署到不同设施上(包含百 KB 级内存的轻量设施)。另外,通过 平台适配层的设计 ,构建了 跨 OS 平台的基础设施。
- 通过基于 TS 扩大的申明式 UI 开发范式,提供了更简洁更天然的开发体验。在运行时方面,在上述的根底上,联合语言运行时的类型优化 ,以及 渲染运行时的扁平化流水线技术 等,进一步晋升性能体验。
申明式开发范式
- 装璜器
用来装璜类、构造体、办法以及变量,赋予其非凡的含意,如上述示例中 @Entry、@Component、@State 都是装璜器。具体而言,@Component 示意这是个自定义组件;@Entry 则示意这是个入口组件;@State 示意组件中的状态变量,此状态变动会引起 UI 变更。 - 自定义组件
可复用的 UI 单元,可组合其它组件,如上述被 @Component 装璜的 struct Hello。 - UI 形容
申明式的形式来形容 UI 的构造,如上述 build() 办法外部的代码块。 - 内置组件
框架中默认内置的根底和布局组件,可间接被开发者调用,比方示例中的 Column、Text、Divider、Button。 - 事件办法
用于增加组件对事件的响应逻辑,对立通过事件办法进行设置,如追随在 Button 前面的 onClick()。 - 属性办法
用于组件属性的配置,对立通过属性办法进行设置,如 fontSize()、width()、height()、color() 等,可通过链式调用的形式设置多项属性。
从 UI 框架的需要角度,ArkTS 在 TS 的类型零碎的根底上,做了进一步的扩大:定义了各种装璜器 、 自定义组件 和UI 形容机制 ,再配合 UI 开发框架中的 UI 内置组件、事件办法、属性办法等独特形成了利用开发的主体。在利用开发中,除了 UI 的结构化形容之外,还有一个重要的方面: 状态治理 。如上述示例中,用 @State 装璜过的变量 myText,蕴含了一个根底的状态管理机制,即 myText 的值的变动会 主动触发相应的 UI 变更 (Text 组件)。ArkUI 中进一步提供了多维度的状态管理机制。和 UI 相关联的数据,不仅能够在组件内应用,还能够在不同组件层级间传递,比方父子组件之间,爷孙组件之间,也能够是全局范畴内的传递,还能够是跨设施传递。另外,从数据的传递模式来看,可分为 只读的单向传递 和可变更的双向传递。开发者能够灵便的利用这些能力来实现数据和 UI 的联动。
具体可参考:https://developer.harmonyos.com/cn/docs/documentation/doc-gui…
ArkTS 开发实际
申明式 UI 基本概念
利用界面是由一个个页面组成,ArkTS 是由 ArkUI 框架提供,用于以申明式开发范式开发界面的语言。
申明式 UI 构建页面的过程,其实是组合组件的过程,申明式 UI 的思维,次要体现在两个方面:
- 形容 UI 的出现后果,而不关怀过程
- 状态驱动视图更新
相似苹果的 SwiftUI 中通过组合视图 View,安卓 Jetpack Compose 中通过组合 @Composable 函数,ArkUI 作为 HarmonyOS 利用开发的 UI 开发框架,其应用 ArkTS 语言构建自定义组件,通过组合自定义组件实现页面的构建。
自定义组件的组成
ArkTS 通过 struct 申明组件名,并通过 @Component 和 @Entry 装璜器,来形成一个自定义组件。
应用 @Entry 和 @Component 装璜的自定义组件作为页面的入口,会在页面加载时首先进行渲染。
@Entry
@Component
struct ToDoList {...}
例如 ToDoList 组件对应如下整个代办页面。
应用 @Component 装璜的自定义组件,如 ToDoItem 这个自定义组件则对应如下内容,作为页面的组成部分。
@Component
struct ToDoItem {...}
在自定义组件内须要应用 build 办法来进行 UI 形容。
@Entry
@Component
struct ToDoList
...
build() {...}
}
build 办法内能够包容内置组件和其余自定义组件,如 Column 和 Text 都是内置组件,由 ArkUI 框架提供,ToDoItem 为自定义组件,须要开发者应用 ArkTS 自行申明。
@Entry
@Component
struct ToDoList {
...
build() {Column(...) {Text(...)
...
ForEach(...{TodoItem(...)
},...)
}
...
}
}
配置属性与布局
自定义组件的组成应用根底组件和容器组件等内置组件进行组合。但有时内置组件的款式并不能满足咱们的需要,ArkTS 提供了属性办法用于形容界面的款式。属性办法反对以下应用形式:
-
常量传递
例如应用 fontSize(50)来配置字体大小。Text('Hello World') .fontSize(50)
-
变量传递
在组件内定义了相应的变量后,例如组件外部成员变量 size,就能够应用 this.size 形式应用该变量。Text('Hello World') .fontSize(this.size)
-
链式调用
在配置多个属性时,ArkTS 提供了链式调用的形式,通过 ’.’ 形式间断配置。Text('Hello World') .fontSize(this.size) .width(100) .height(100)
-
表达式传递
属性中还能够传入一般表达式以及三目运算表达式。Text('Hello World') .fontSize(this.size) .width(this.count + 100) .height(this.count % 2 === 0 ? 100 : 200)
-
内置枚举类型
除此之外,ArkTS 中还提供了内置枚举类型,如 Color,FontWeight 等,例如设置 fontColor 扭转字体色彩为红色,并公有 fontWeight 为加粗。Text('Hello World') .fontSize(this.size) .width(this.count + 100) .height(this.count % 2 === 0 ? 100 : 200) .fontColor(Color.Red) .fontWeight(FontWeight.Bold)
对于有多种组件须要进行组合时,容器组件则是形容了这些组件应该如何排列的后果。
ArkUI 中的布局容器有很多种,在不同的实用场合抉择不同的布局容器实现,ArkTS 应用容器组件采纳花括号语法,外部搁置 UI 形容。
这里咱们将介绍最根底的两个布局——列布局和行布局。
对于如下每一项的布局,两个元素为横向排列,抉择Row 布局
Row() {Image($r('app.media.ic_default'))
...
Text(this.content)
...
}
...
相似下图所示的布局,整体都是从上往下纵向排列,实用的布局形式是Column 列布局。
Column() {Text($r('app.string.page_title'))
...
ForEach(this.totalTasks,(item) => {TodoItem({content:item})
},...)
}
扭转组件状态
理论开发中因为交互,页面的内容可能须要产生变动,以每一个 ToDoItem 为例,其在实现时的状态与未实现时的展现成果是不一样的。
申明式 UI 的特点就是 UI 是随数据更改而主动刷新的,咱们这里定义了一个类型为 boolean 的变量 isComplete,其被 @State装璜后,框架内 建设了数据和视图之间的绑定,其值的扭转影响 UI 的显示。
@State isComplete : boolean = false;
用圆圈和对勾这样两个图片,别离来示意该项是否实现,这部分波及到内容的切换,须要应用 条件渲染 if / else 语法 来进行组件的显示与隐没,当判断条件为真时,组件为已实现的状态,反之则为未实现。
if (this.isComplete) {Image($r('app.media.ic_ok'))
.objectFit(ImageFit.Contain)
.width($r('app.float.checkbox_width'))
.height($r('app.float.checkbox_width'))
.margin($r('app.float.checkbox_margin'))
} else {Image($r('app.media.ic_default'))
.objectFit(ImageFit.Contain)
.width($r('app.float.checkbox_width'))
.height($r('app.float.checkbox_width'))
.margin($r('app.float.checkbox_margin'))
}
因为两个 Image 的实现具备大量反复代码,ArkTS 提供了 @Builder 装璜器,来润饰一个函数,疾速生成布局内容,从而能够防止反复的 UI 形容内容。这里应用 @Bulider 申明了一个 labelIcon 的函数,参数为 url,对应要传给 Image 的图片门路。
@Builder labelIcon(url) {Image(url)
.objectFit(ImageFit.Contain)
.width($r('app.float.checkbox_width'))
.height($r('app.float.checkbox_width'))
.margin($r('app.float.checkbox_margin'))
}
应用时只须要应用 this 关键字拜访 @Builder 装璜的函数名,即可疾速创立布局。
if (this.isComplete) {this.labelIcon($r('app.media.ic_ok'))
} else {this.labelIcon($r('app.media.ic_default'))
}
为了让待办项带给用户的体验更合乎已实现的成果,给内容的字体也减少了相应的款式变动,这里应用了三目运算符来依据状态变动批改其透明度和文字款式,如 opacity 是管制透明度,decoration 是文字是否有划线。通过 isComplete 的值来管制其变动。
Text(this.content)
...
.opacity(this.isComplete ? CommonConstants.OPACITY_COMPLETED : CommonConstants.OPACITY_DEFAULT)
.decoration({type: this.isComplete ? TextDecorationType.LineThrough : TextDecorationType.None})
最初,为了实现与用户交互的成果,在组件上增加了 onClick 点击事件,当用户点击该待办项时,数据 isComplete 的更改就可能触发 UI 的更新。
@Component
struct ToDoItem {
@State isComplete : boolean = false;
@Builder labelIcon(icon) {...}
...
build() {Row() {if (this.isComplete) {this.labelIcon($r('app.media.ic_ok'))
} else {this.labelIcon($r('app.media.ic_default'))
}
...
}
...
.onClick(() => {this.isComplete= !this.isComplete;})
}
}
循环渲染列表数据
刚刚只是实现了一个 ToDoItem 组件的开发,当咱们有多条待办数据须要显示在页面时,就须要应用到 ForEach 循环渲染语法。
例如这里咱们有五条待办数据须要展现在页面上。
total_Tasks:Array<string> = [
'早起晨练',
'筹备早餐',
'浏览名著',
'学习 ArkTS',
'看剧放松'
]
ForEach 根本应用中,只须要理解要渲染的数据以及要生成的 UI 内容两个局部,例如这里要渲染的数组为以上的五条待办事项,要渲染的内容是 ToDoItem 这个自定义组件,也能够是其余内置组件。
ToDoItem 这个自定义组件中,每一个 ToDoItem 要显示的文本参数 content 须要内部传入,参数传递应用花括号的模式,用 content 承受数组内的内容项 item。
最终实现的代码及其成果如下。
@Entry
@Component
struct ToDoList {
...
build() {Row() {Column() {Text(...)
...
ForEach(this.totalTasks,(item) => {TodoItem({content:item})
},...)
}
.width('100%')
}
.height('100%')
}
}
参考
- https://developer.huawei.com/consumer/cn/training/course/slig…
- https://developer.huawei.com/consumer/cn/training/course/slig…
- https://developer.harmonyos.com/cn/docs/documentation/doc-gui…