内容学习来自华为开发者学习网站
目录
3.2.1 基于ArkTS的声明式开发范式(声明式开发范式)(开发新应用推荐)
认识ArkTS开发语言
1.ArkTS
1.1 认识ArkTS
ArkTS是HarmonyOS的主力应用开发语言。
它在 TypeScript(TS)的基础上,匹配ArkUI框架,扩展了声明式UI、状态管理等相应的能力。
ArkTS、TypeScript、JavaScript的关系:
-
JavaScript
一种属于网络的高级脚本语言,被广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果
-
TypeScript
JavaScript的超集,扩展了JavaScript的语法,通过在JavaScript的基础上添加静态类型定义构建而成,是一个开源的编程语言
-
ArkTS
兼容TypeScript语言,扩展了 声明式UI、状态管理、并发任务等能力
因为 ArkTS 是 TypeScript的拓展,因此在学习 ArkTS 之前要先了解 TypeScript的语法知识
1.2 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()。
2.TypeScript基础语法介绍
2.1 基础类型
2.1.1 布尔值(boolean)
TypeScript中可以使用 Boolean 来表示这个变量是布尔值,可以赋值为true或者false。
let isDone:boolean = false;
2.1.2 数字(number)
TypeScript里的 所有数字都是浮点数 ,这些浮点数的 类型是number。除了 支持十进制,还支持二进制、八进制、十六进制。
let decLiteral:number = 2023;
console.log('decLiteral is'+decLiteral);
let binaryLiteral:number = 0b11111100111;
console.log('binaryLiteral is'+binaryLiteral);
let octalLiteral:number = 0o3747;
console.log('octalLiteral is'+octalLiteral);
let hexLiteral:number = 0x7e7;
console.log('hexLiteral is'+hexLiteral);
2.1.3 字符串(string)
TypeScript里使用string表示文本数据类型,可以使用双引号(")或单引号(')表示字符串。
let name:string="Jacky";
name="Tom";
name='Mick';
2.1.4 数组(object)
TypeScript支持以下两种方式声明数组:第一种,可以在元素类型后面接上[],表示由此类型元素组成的一个数组;第二种方式是使用数组泛型,Array<元素类型>。
let list1:number[]=[1,2,3];
let list2:Array<number>=[1,2,3];
2.1.5 元组(object)
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
let x:[string,number];
x = ['hello',10]//ok
x = [10,'hello']//error
2.1.6 枚举
enum类型是对JavaScript标准数据类型的一个补充,使用枚举类型可以为一组数值赋予友好的名字。
enum Color{Red,Green,Blue};
let c:Color = Color.Green;
2.1.7 unknown
有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。那么我们可以使用unknown类型来标记这些变量。
let notSure:unknown = 4;
notSure = 'maybe a string instead';
notSure = false;
2.1.8 void
当一个函数没有返回值时,你通常会见到其返回值类型是void。
function test():void{
console.log('This is function is void');
}
2.1.9 null和undefined
TypeScript里,undefined和null两者各自有自己的类型分别叫做undefined和null。
let u:undefined = undefined;
let n:null = null;
2.1.10 联合类型
联合类型(union types)表示取值可以为多种类型中的一种。
let myFavouriteNumber:string|number;
myFavouriteNumber = 'seven';
myFavouriteNumber = 7;
2.2 条件语句
条件语句用于基于不同的条件来执行不同的动作。TypeScript条件语句是通过一条或多条语句的执行结果(true或false)来决定执行的代码块。
2.2.1 if语句
let num:number = 5;
if(num>0){
console.log('数字是正数');
}
2.2.2 if...else语句
let num:number = 12;
if(num%2==0){
console.log('偶数');
}else{
console.log('奇数');
}
2.2.3 if...else if...else语句
let num:number = 5;
if(num>0){
console.log(num + '是正数');
}else if(num<0){
console.log(num + '是负数');
}else{
console.log(num + '为0');
}
除了可以通过if...else语句进行条件判断外,还可以通过switch...case语句进行条件判断。
2.2.4 switch...case语句
一个switch语句允许测试一个变量等于多个值时的情况。每个值称为一个case,且被测试的变量会对每个switch case进行检查。
var grade:string = 'A';
switch(grade){
case'A':{
console.log('优');
break;
}
case'B':{
console.log('良');
break;
}
case'C':{
console.log('及格');
break;
}
case'D':{
console.log('不及格');
break;
}
default:{
console.log('非法输入');
break;
}
}
2.3 函数
2.3.1 函数
函数是一组一起执行一个任务的语句,函数声明要告诉编译器函数的名称、返回类型和参数。TypeScript可以创建 有名字的函数 和 匿名函数,其创建方法如下:
//有名函数
function add(x,y){
return x+y;
}
//匿名函数
let myAdd = function(x,y){
return x+y;
};
2.3.2 为函数定义类型
为了确保输入输出的准确性,我们可以为上面那个函数添加类型
//有名函数:给变量设置为number类型
function add(x:number,y:number):number{
return x+y;
}
//匿名函数:给变量设置为number类型
let myAdd = function(x:number,y:number):number{
return x+y;
};
2.3.3 函数的可选参数
在TypeScript里我们可以在 参数名旁使用(?)实现可选参数的功能。比如,我们想让lastName是可选的:
function buildName(firstName:string,lastName?:string){
if(lastName){
return firstName + '' + lastName;
}else{
return firstName;
}
}
let result1 = buildName('Bob');
let result2 = buildName('Bob','Adams');
2.3.4 函数的剩余参数
剩余参数会被当做 个数不限的可选参数。 可以一个都没有,同样也可以有任意个。 可以使用省略号( ...)进行定义:
function getEmployeeName(firstName: string, ...restOfName: string[]) {
return firstName + ' ' + restOfName.join(' ');
}
let employeeName = getEmployeeName('Joseph', 'Samuel', 'Lucas', 'MacKinzie');
2.3.5 箭头函数
ES6版本的TypeScript提供了一个箭头函数,它是 定义匿名函数的简写语法,用于函数表达式,它省略了function关键字。箭头函数的定义如下,其函数是一个语句块:
( [param1, parma2,…param n] )=> {
// 代码块
}
其中,括号内是函数的入参,可以有0到多个参数,箭头后是函数的代码块。我们可以将这个箭头函数赋值给一个变量,如下所示:
let arrowFun = ( [param1, parma2,…param n] )=> {
// 代码块
}
如何要主动调用这个箭头函数,可以按如下方法去调用:
arrowFun(param1, parma2,…param n)
接下来我们看看如何将我们 熟悉的函数定义方式转换为箭头函数。我们可以定义一个判断正负数的函数,如下:
function testNumber(num: number) {
if (num > 0) {
console.log(num + ' 是正数');
} else if (num < 0) {
console.log(num + ' 是负数');
} else {
console.log(num + ' 为0');
}
}
其调用方法如下:
testNumber(1) //输出日志:1 是正数
如果将这个函数定义为箭头函数,定义如下所示:
let testArrowFun = (num: number) => {
if (num > 0) {
console.log(num + ' 是正数');
} else if (num < 0) {
console.log(num + ' 是负数');
} else {
console.log(num + ' 为0');
}
}
其调用方法如下:
testArrowFun(-1) //输出日志:-1 是负数
后面,我们在学习HarmonyOS应用开发时会经常用到箭头函数。例如,给一个按钮添加点击事件,其中onClick事件中的函数就是箭头函数。
Button("Click Now")
.onClick(() => {
console.info("Button is click")
})
2.4 类
TypeScript支持基于类的面向对象的编程方式,定义类的关键字为 class,后面紧跟类名。类描述了所创建的对象共同的属性和方法。
2.4.1 类的定义
例如,我们可以声明一个Person类,这个类有3个成员:一个是属性(包含name和age),一个是构造函数,一个是getPersonInfo方法,其定义如下所示。
class Person {
private name: string
private age: number
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public getPersonInfo(): string {
return `My name is ${this.name} and age is ${this.age}`;
}
}
let person1 = new Person('Jacky',18);
person1.getPersonInfo();
2.4.2 继承
继承就是子类继承父类的特征和行为,使得字类具有父类相同的行为。TypeScript中允许使用继承来扩展现有的类,对应的关键字为extends
class Employee extends Person {
private department: string
constructor(name: string, age: number, department: string) {
super(name, age);
this.department = department;
}
public getEmployeeInfo(): string {
return this.getPersonInfo() + `and work in ${this.department}`;
}
}
let person2 = new Employee('Tom',28,'HuaWei');
person2.getPersonInfo();
person2.getEmployeeInfo();
2.5 模块
随着应用越来越大,通常要将代码拆分成多个文件,即所谓的模块(module)。模块可以相互加载,并可以使用特殊的指令export和import来交换功能,从另一个模块调用一个模块的函数。
两个模块之间的关系是通过在文件级别上使用import和export建立的。模块里面的变量、函数和类等在模块外部是不可见的,除非明确地使用export导出它们。类似地,我们必须通过import导入其他模块导出的变量、函数、类等
export class NewsData{
title: string;
content: string;
constructor(title: string,content: string){
this.title = title;
this.content = content;
}
}
import { NewsData } from '../common/bean/NewsData';
2.6 迭代器
当一个对象实现了Symbol.iterator属性时,我们认为他是可迭代的。一些内置的类型如Array,Map,Set,String,Int32Array,Unit32Array等都具有可迭代性
for..of语句
let someArray = [1,'string',false];
for(let entry of someArray){
console.log(entry);//1,'string',false
}
for..in语句 vs for..of语句
let list = [4,5,6];
for(let i in list){
console.log(i);//'0','1','2'
}
for(let i of list){
console.log(i);//'4','5','6'
}
3.ArkUI开发框架(方舟开发框架)
方舟开发框架(ArkUI)为HarmonyOS应用的UI开发提供了完整的基础设施,包括简洁的UI语法、丰富的UI功能(组件、布局、动画以及交互事件),以及实时界面预览工具等,可以支持开发者进行可视化界面开发。
3.1 基本概念
-
UI:即用户界面。开发者可以将应用的用户界面设计为多个功能页面,每个页面进行单独的文件管理,并通过页面路由API完成页面间的调度管理如跳转、回退等操作,以实现应用内的功能解耦
-
组件:UI构建与显示的最小单位,如列表、网络、按钮、单选框、进度条、文本等。开发者通过多种组件的组合,构建出满足自身应用诉求的完整界面
3.2 两种开发范式
3.2.1 基于ArkTS的声明式开发范式(声明式开发范式)(开发新应用推荐)
采用基于TypeScript声明式UI语法扩展而来的ArkTS语言,从组件、动画和状态管理三个维度提供UI绘制能力
为什么开发新应用推荐声明式开发范式
-
开发效率:声明式开发范式更接近自然语义的编程方式,开发者可直观地描述UI,无需关心如何实现UI绘制和渲染,开发高效简洁
-
应用性能:两种开发范式地UI后端引擎和语言运行时是共用的,但相比类Web开发范式,声明式开发范式无需JS框架进行页面DOM管理,渲染更新链路更为精简,占用内存更少,应用性能更佳
-
发展趋势:声明式开发范式后续会作为主推的开发范式持续演进,为开发者提供更丰富、更强大的能力
3.2.2 兼容JS的类Web开发范式(类Web开发范式)
采用经典的HML、CSS、JavaScript三段式开发方式,即使用HML标签文件搭建布局、使用CSS文件描述样式、使用JavaScript文件处理逻辑。该范式更符合Web前端开发者的使用习惯,便于快速将已有的Web应用改造成方舟开发框架应用
3.2.3 不同应用类型支持的开发范式
应用模型 | 页面形态 | 支持的UI开发范式 |
---|---|---|
Stage模型(推荐) | 应用或服务的页面 | 声明式开发范式(推荐) |
卡片 | 声明式开发范式(推荐) 类Web开发范式 | |
FA模型 | 应用或服务的页面 | 声明式开发范式 类Web开发范式 |
卡片 | 类Web开发范式 |
4.UI开发——ArkTS声明式开发范式
4.1 概述
基于ArkTS的声明式开发范式的方舟开发框架是一套开发极简、高性能、支持跨设备的UI开发框架,提供了构建HarmonyOS应用UI所必需的能力,主要包括:
-
ArkTS
ArkTS 是UI开发语言,基于TypeScript(TS)语言扩展而来,是TS的超集。扩展能力包括各种 装饰器、自定义组件、UI描述机制。状态数据管理作为基于ArkTS的声明式开发范式的特色,通过功能不同的装饰器给开发者提供了清晰的页面更新渲染流程和管道。状态管理包括UI组件状态和应用程序状态,两者协作可以使开发者完整地构建整个应用的数据更新和UI渲染
-
布局
布局是UI的必要元素,它定义了组件在界面中的位置。ArkUI框架提供了多种布局方式,除了基础的线性布局、层叠布局、弹性布局、相对布局、栅格布局外,也提供了相对复杂的列表、宫格、轮播
-
组件
组件是UI的必要元素,形成了在界面中的样子,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件。系统内置组件包括按钮、单选框、进度条、文本等。开发者可以通过链式调用的方式设置系统内置组件的渲染效果。开发者可以将系统内置组件组合为自定义组件,通过这种方式将页面组件化为一个个独立的UI单元,实现页面不同单元的独立创建、开发和复用,具有更强的工程性
-
页面路由和组件导航
应用可能包含多个页面,可通过页面路由实现页面间的跳转。一个页面内可能存在组件间的导航如典型的分栏,可通过导航组件实现组件间的导航
-
图形
方舟开发框架提供了多种类型图片的显示能力和多种自定义绘制的能力,以满足开发者的自定义绘图需求,支持绘制形状、填充颜色、绘制文本、变形与裁剪、嵌入图片等
-
动画
动画是UI的重要元素之一。优秀的动画设计能够极大地提升用户体验,框架提供了丰富的动画能力,除了组件内置动画效果外,还包括属性动画、显示动画、自定义转场动画以及动画API等,开发者可以通过封装的物理模型或者调用动画能力API来实现自定义动画轨迹
-
交互事件
交互事件是UI和用户交互的必要元素。方舟开发框架提供了多种交互事件,除了触摸事件、鼠标事件、键盘按键事件、焦点事件等通用事件外,还包括基于通用事件进行进一步识别的手势事件。手势事件有单一手势事件、长按手势、拖动手势、捏合手势、旋转手势、滑动手势,以及通过单一手势事件进行组合的组合手势事件
4.2 特点
-
开发效率高,开发体验好
-
代码简洁:通过接近自然语义的方式描述UI,不必关心框架如何实现UI绘制和渲染
-
数据驱动UI变化:让开发者更专注自身业务逻辑的处理。当UI发生变化时,开发者无需编写在不同的UI之间进行切换的UI代码,开发人员仅需要编写引起界面变化的数据,具体UI如何变化交给框架
-
开发体验好:界面也是代码,编程体验得到提升
-
-
性能优越
-
声明式UI前端和UI后端分层:UI后端采用C++语言构建,提供对应前端的基础组件、布局、动效、交互事件、组件状态管理和渲染管线
-
语言编译器和运行时的优化:统一字节码、高效FFI-Foreign Function Interface、AOT-Ahead Of Time、引擎极小化、类型优化等
-
-
生态容易快速推进
能够借力主流语言生态快速推进,语言相对中立友好,有相应的标准组织可以逐步推进
4.3 框架
-
声明式UI前端
提供UI开发范式的基础语言规范,并提供内置的UI组件、布局和动画,提供了多种状态管理机制,为应用开发者提供一系列接口支持
-
语言运行时
选用方舟语言运行时,提供了针对UI范式语法的解析能力、跨语言调用支持的能力和TS语言高性能运行环境
-
声明式UI后端引擎
后端引擎提供了兼容不同开发范式的UI渲染管线,提供多种基础组件、布局计算、动效、交互事件,提供了状态管理和绘制能力
-
渲染引擎
提供了高效的绘制能力,将渲染管线收集的渲染指令,绘制到屏幕的能力
-
平台适配层
提供了对系统平台的抽象接口,具备接入不同系统的能力,如系统渲染管线、生命周期调度等