「鸿蒙」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@Componentstruct ToDoList {...}

例如ToDoList组件对应如下整个代办页面。

应用@Component装璜的自定义组件,如ToDoItem这个自定义组件则对应如下内容,作为页面的组成部分。

@Componentstruct ToDoItem {...}

在自定义组件内须要应用build办法来进行UI形容。

@Entry@Component struct ToDoList   ...   build() {    ...  } }

build办法内能够包容内置组件和其余自定义组件,如Column和Text都是内置组件,由ArkUI框架提供,ToDoItem为自定义组件,须要开发者应用ArkTS自行申明。

@Entry@Componentstruct 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的更新。

@Componentstruct 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@Componentstruct 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...