ArkTS

参考文档:初识ArkTS语言-学习ArkTS语言-基础入门 | 华为开发者联盟 (huawei.com)

环境

安装版本:DevEco Studio NEXT Developer Beta2 (2024/07/20)

创建工程

文件>新建项目>Application>Empty Ability

Hello World

// 导入页面路由模块
import { router } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
        // 添加按钮,以响应用户点击
        Button() {
          Text('Next')
            .fontSize(30)
            .fontWeight(FontWeight.Bold)
        }
        .type(ButtonType.Capsule)
        .margin({
          top: 20
        })
        .backgroundColor('#0D9FFB')
        .width('40%')
        .height('5%')
        // 跳转按钮绑定onClick事件,点击时跳转到第二页
        .onClick(() => {
          console.info(`Succeeded in clicking the 'Next' button.`)
          // 跳转到第二页
          router.pushUrl({ url: 'pages/Second' }).then(() => {
            console.info('Succeeded in jumping to the second page.')

          }).catch((err: BusinessError) => {
            console.error(`Failed to jump to the second page. Code is ${err.code}, message is ${err.message}`)
          })
        })
      }
      .width('100%')
    }
    .height('100%')
  }
}
添加第二个页面

配置路由entry / src / main / resources / base / profile / main_pages.json:

{
  "src": [
    "pages/Index",
    "pages/Second"
  ]
}

第二个页面:

// Second.ets
// 导入页面路由模块
import { router } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Second {
  @State message: string = 'Hi there'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
        Button() {
          Text('Back')
            .fontSize(25)
            .fontWeight(FontWeight.Bold)
        }
        .type(ButtonType.Capsule)
        .margin({
          top: 20
        })
        .backgroundColor('#0D9FFB')
        .width('40%')
        .height('5%')
        // 返回按钮绑定onClick事件,点击按钮时返回到第一页
        .onClick(() => {
          console.info(`Succeeded in clicking the 'Back' button.`)
          try {
            // 返回第一页
            router.back()
            console.info('Succeeded in returning to the first page.')
          } catch (err) {
            let code = (err as BusinessError).code; 
            let message = (err as BusinessError).message; 
            console.error(`Failed to return to the first page. Code is ${code}, message is ${message}`)
          }
        })
      }
      .width('100%')
    }
    .height('100%')
  }
}
页面跳转

在 Index.ets 导入页面路由模块 router:

// Index.ets
// 导入页面路由模块
import { router } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

将 Next 按钮绑定 onClick 事件:

// Index.ets
// ...
        // 添加按钮,以响应用户点击
        Button() {
          Text('Next')
            .fontSize(30)
            .fontWeight(FontWeight.Bold)
        }
        .type(ButtonType.Capsule)
        .margin({
          top: 20
        })
        .backgroundColor('#0D9FFB')
        .width('40%')
        .height('5%')
        // 跳转按钮绑定onClick事件,点击时跳转到第二页
        .onClick(() => {
          console.info(`Succeeded in clicking the 'Next' button.`)
          // 跳转到第二页
          router.pushUrl({ url: 'pages/Second' }).then(() => {
            console.info('Succeeded in jumping to the second page.')

          }).catch((err: BusinessError) => {
            console.error(`Failed to jump to the second page. Code is ${err.code}, message is ${err.message}`)
          })
        })

Second.ets 的 back 按钮类似。

效果

ArkTS 基本组成

基础

声明

变量

关键字 let

let hi: string = 'hello';
hi = 'hello, world';

常量

关键字 const

const hi: string = 'hello';

自动类型推断

有初始值时,不用显示指定类型

let hi = 'hello';

类型

Number 类型

包括整数和浮点数

let n1 = 3.14;
let n2 = 3.141592;
let n3 = .5;
let n4 = 1e10;
// 阶乘
function factorial(n: number): number {
  if (n <= 1) {
    return 1;
  }
  return n * factorial(n - 1);
}

Boolean 类型

true 和 false

let isDone: boolean = false;

// ...

if (isDone) {
  console.log ('Done!');
}

String 类型

(’)或(")或(`)

let s1 = 'Hello, world!\n';
let s2 = 'this is a string';
let a = 'Success';
let s3 = `The result is ${a}`;

Void 类型

用于指定函数没有返回值

// 定义一个返回类型为 void 的函数
function logMessage(message: string): void {
    console.info(message);
}

Object 类型

对象

Array 类型

数组

let names: string[] = ['Alice', 'Bob', 'Carol'];

Enum 类型 | 枚举类型

enum ColorSet { White = 0xFF, Grey = 0x7F, Black = 0x00 }
let c: ColorSet = ColorSet.Black;

Union 类型

联合类型,由多个类型组合成的引用类型

class Cat { sleep () {}; meow () {} }
class Dog { sleep () {}; bark () {} }
class Frog { sleep () {}; leap () {} }

type Animal = Cat | Dog | Frog | number

let animal: Animal = new Frog();
if (animal instanceof Frog) {
  let frog: Frog = animal as Frog; // animal在这里是Frog类型
  animal.leap();
  frog.leap();
  // 结果:青蛙跳了两次
}

animal.sleep (); // 任何动物都可以睡觉

Aliases 类型

为匿名类型(数组、函数、对象字面量或联合类型)提供名称,或为已有类型提供替代名称。

type Matrix = number[][];
type Handler = (s: string, no: number) => string;
type Predicate <T> = (x: T) => Boolean;
type NullableObject = Object | null;

运算符

赋值

=

复合赋值

+=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、|=、^=

比较

==、!=、>、>=、<、<=

算术

一元

-、+、–、++

二元

-、+、*、/、%

位运算符

运算符 说明
a & b 按位与:如果两个操作数的对应位都为1,则将这个位设置为1,否则设置为0。
a | b 按位或:如果两个操作数的相应位中至少有一个为1,则将这个位设置为1,否则设置为0。
a ^ b 按位异或:如果两个操作数的对应位不同,则将这个位设置为1,否则设置为0。
~ a 按位非:反转操作数的位。
a << b 左移:将a的二进制表示向左移b位。
a >> b 算术右移:将a的二进制表示向右移b位,带符号扩展。
a >>> b 逻辑右移:将a的二进制表示向右移b位,左边补0。

逻辑运算符

&&、|| 、!

语句

If 语句

if (condition1) {
  // 语句1
} else if (condition2) {
  // 语句2
} else {
  // else语句
}

Switch 语句

switch (expression) {
  case label1: // 如果label1匹配,则执行
    // ...
    // 语句1
    // ...
    break; // 跳出 switch
  case label2:
  case label3: // 如果label2或label3匹配,则执行
    // ...
    // 语句2, 语句3
    // ...
    break; // 可省略
  default:
    // 默认语句
}

条件表达式

// 真为 1 ,假为 2
condition ? expression1 : expression2

For 语句

let sum = 0;
for (let i = 0; i < 10; i += 2) {
  sum += i;
}
For – of 语句

用于遍历数组或字符串

for (let char of 'a string object') {
  // 语句
}

While 语句

let n = 0;
let x = 0;
while (n < 3) {
  n++;
  x += n;
}
Do-while 语句
let i = 0;
do {
  i += 1;
} while (i < 10)

Break 语句

终止

Continue语句

停止当前循环迭代,并将控制传递给下一个迭代

Throw 和 Try语句

throw 语句用于抛出异常或错误

throw new Error('this error')

try语句用于捕获和处理异常或错误

try {
  // 可能发生异常的语句块
} catch (e) {
  // 异常处理
} finally {
  // 语句    
}

函数

函数声明

function add(x: string, y: string): string {
  let z: string = `${x} ${y}`;
  return z;
}

可选参数 | name?: Type

调用函数时可省略的参数

可为可选参数设置参数默认值

function multiply(n: number, coeff: number = 2): number {
  return n * coeff;
}
multiply(2);  // 返回2*2
multiply(2, 3); // 返回2*3

Rest 参数

用在函数的最后一个参数,允许函数或方法接受任意数量的实参

function sum(...numbers: number[]): number {
  let res = 0;
  for (let n of numbers)
    res += n;
  return res;
}

sum() // 返回0
sum(1, 2, 3) // 返回6

返回类型

可以显示指定,可推断

// 显式指定返回类型
function foo(): string { return 'foo'; }

// 推断返回类型为string
function goo() { return 'goo'; }

函数的作用域

函数中定义的变量和其他实例仅可以在函数内部访问,不能从外部访问。

如果函数中定义的变量与外部作用域中已有实例同名,则函数内的局部变量定义将覆盖外部定义。

函数类型

函数类型通常用于定义回调:

type trigFunc = (x: number) => number // 这是一个函数类型

function do_action(f: trigFunc) {
   f(3.141592653589); // 调用函数
}
// 将函数作为参数传入, 相当于 Math.sin(3.141592653589)
do_action(Math.sin); 

箭头函数

// 返回类型可省略
let sum = (x: number, y: number): number => {
  return x + y;
}
// 等价
let sum1 = (x: number, y: number) => { return x + y; }
let sum2 = (x: number, y: number) => x + y

闭包

// 外部函数, 外部参数
function outerFunction(outerVariable: string) {
    // 返回内部函数, 且该内部函数保持了对外部参数、内部参数的引用
    return function innerFunction(innerVariable: string) {
        console.log('Outer Variable: ' + outerVariable);
        console.log('Inner Variable: ' + innerVariable);
    }
}

// 执行外部函数 outerFunction()
// 然后 newFunction 对其返回的 innerFunction() 实例引用
// 同时维持 innerFunction() 实例的环境引用, 包括 'outside'
const newFunction = outerFunction('outside');
newFunction('inside');

计数器

// 外部函数
function createCounter() {
    let count = 0;
    return function() {
        count++;
        return count;
    }
}

// counter 维持了对 count 的引用
const counter = createCounter();
console.log(counter()); // 输出: 1
console.log(counter()); // 输出: 2
console.log(counter()); // 输出: 3

函数重载

// 定义重载签名
function foo(x: number): void;
function foo(x: string): void;
// 定义实现签名
function foo(x: number | string): void {
  if (typeof x === 'number') {
    console.log(x.toString());
  }else {
    console.log(x)
  }
}
foo(123);     // 使用第一个定义
foo('aa');    // 使用第二个定义

类声明引入一个新类型,并定义其字段、方法和构造函数。

class Person {
  name: string = ''
  age: number = 0
  constructor (n: string) {
    this.name = n;
  }
  fullName(): string {
    return this.name;
  }
}

字段

在类中声明的某种类型的变量。

实例字段

存于实例,使用实例名访问。

静态字段

使用关键字 static 将字段声明为静态。

类的所有实例共享一个静态字段。

使用类名访问静态字段。

class Person {
  static numberOfPersons = 0
  constructor() {
     // ...
     Person.numberOfPersons++;
     // ...
  }
}

Person.numberOfPersons;

字段初始化

所有字段在声明时或者构造函数中显式初始化。

class Person {
  name: string // 没有初始化, 可能为 undefined

  setName(n:string): void {
    this.name = n;
  }

  getName(): string {
    // 开发者使用"string"作为返回类型,这隐藏了name可能为"undefined"的事实。
    // 更合适的做法是将返回类型标注为"string | undefined",以告诉开发者这个API所有可能的返回值。
    return this.name;
  }
}

let jack = new Person();
// 假设代码中没有对name赋值,例如调用"jack.setName('Jack')"
jack.getName().length; // 运行时异常:name is undefined

getter 和 setter

class Person {
  name: string = ''
  private _age: number = 0
  get age(): number { return this._age; }
  set age(x: number) {
    if (x < 0) {
      throw Error('Invalid age argument');
    }
    this._age = x;
  }
}

let p = new Person();
p.age; // 输出0
p.age = -42; // 设置无效age值会抛出错误

方法

实例方法

存于实例,使用实例名访问。

静态方法

使用关键字 static 将方法声明为静态。

通过类名调用静态方法。

class Cl {
  static staticMethod(): string {
    return 'this is a static method.';
  }
}
console.log(Cl.staticMethod());

继承

一个类可以继承另一个类(称为基类),并使用实现多个接口:

class [extends BaseClassName] [implements listOfInterfaces] {
  // ...
}

继承类继承基类的字段和方法,但不继承构造函数。

继承类可以新增定义字段和方法,也可以覆盖其基类定义的方法。

class Person {
  name: string = ''
  private _age = 0
  get age(): number {
    return this._age;
  }
}
class Employee extends Person {
  salary: number = 0
  calculateTaxes(): number {
    return this.salary * 0.42;
  }
}

实现接口的类必须实现列出的接口中定义的所有方法。

父类访问

关键字 super 可用于访问父类的实例字段、实例方法和构造函数

class RectangleSize {
  protected height: number = 0
  protected width: number = 0

  constructor (h: number, w: number) {
    this.height = h;
    this.width = w;
  }

  draw() {
    /* 绘制边界 */
  }
}
class FilledRectangle extends RectangleSize {
  color = ''
  constructor (h: number, w: number, c: string) {
    super(h, w); // 父类构造函数的调用
    this.color = c;
  }

  draw() {
    super.draw(); // 父类方法的调用
    // super.height -可在此处使用
    /* 填充矩形 */
  }
}

方法重写

class RectangleSize {
  // ...
  area(): number {
    // 实现
    return 0;
  }
}
class Square extends RectangleSize {
  private side: number = 0
  area(): number {
    return this.side * this.side;
  }
}

构造函数

class C {
  constructor ([parameters]) {
  // ...
  }
}

如果未定义构造函数,则会自动创建具有空参数列表的默认构造函数。

可见性修饰符

Public(公有)

public 修饰的类成员(字段、方法、构造函数)在程序的任何可访问该类的地方都是可见的。

Private(私有)

private 修饰的成员不能在声明该成员的类之外访问。

Protected(受保护)

protected 修饰符的作用与 private 修饰符非常相似,不同点是 protected修饰的成员允许在派生类(子类)中访问。

class Base {
  protected x: string = ''
  private y: string = ''
}
class Derived extends Base {
  foo() {
    this.x = 'a'; // 访问受保护成员
    this.y = 'b'; // 编译时错误,'y'不可见,因为它是私有的
  }
}

对象字面量

用于更方便地创建类实例并提供一些初始值。

// 定义
class C {
  n: number = 0
  s: string = ''
}
// 创建实例
let c: C = {n: 42, s: 'foo'};

Record类型的对象字面量

用于将类型(键类型)的属性映射到另一个类型(值类型)。

let map: Record<string, number> = {
  'John': 25,
  'Mary': 21,
}

map['John']; // 25
interface PersonInfo {
  age: number
  salary: number
}

let map: Record<string, PersonInfo> = {
  'John': { age: 25, salary: 10},
  'Mary': { age: 21, salary: 20}
}

接口

// 接口:
interface AreaSize {
  area: number // 属性
  calculateAreaSize(): number // 方法的声明
  someMethod(): void;     // 方法的声明
}

// 接口实现:
class RectangleSize implements AreaSize {
  area: number = 0;
  private width: number = 0
  private height: number = 0
  someMethod(): void {
    console.log('someMethod called');
  }
  calculateAreaSize(): number {
    this.someMethod(); // 调用另一个方法并返回结果
    this.area = this.width * this.height
    return this.area;
  }
}

接口继承

interface Style {
  color: string
}

interface ExtendedStyle extends Style {
  width: number
}

泛型类型和函数

使其支持多种数据类型。

泛型类和接口

class CustomStack<Element> {
  public push(e: Element):void {
    console.log(`${e}`)
  }
}
let s = new CustomStack<string>();
s.push('hello');
interface Pair<T, U> {
  first: T;
  second: U;
}

let pair: Pair<number, string> = { first: 1, second: "two" };

<>可以对类型进行约束。

泛型函数

function last<T>(x: T[]): T {
  return x[x.length - 1];
}
last([1, 2, 3]);
last<string>(['aa', 'bb']);

空安全

默认情况下,ArkTS中的所有类型都是不可为空的。

let x: number = null;    // 编译时错误
let y: string = null;    // 编译时错误
let z: number[] = null;  // 编译时错误

let x: number | null = null;
x = 1;    // ok
x = null; // ok
if (x != null) { /* do something */ }

非空断言运算符

使类型不为空,用法为后缀感叹号 !

let b = null;
let x: number;
x = b! + 1;

class C {
  value: number | null = 1;
}

let c = new C();
let y: number;
y = c.value + 1;  // 编译时错误:无法对可空值作做加法
y = c.value! + 1; // ok,值为2

空值合并运算符

??,检查左侧表达式的求值是否等于null或者undefined

如果是,则表达式的结果为右侧表达式;否则,结果为左侧表达式。

class Person {
  // ...
  nick: string | null = null
  getNick(): string {
    return this.nick ?? ''; // 若昵称为空,则返回空字符串
  }
}

可选链

?. ,用于访问对象属性、调用方法以及访问数组元素等场景,

如果该属性是undefined或者null,可选链运算符会返回undefined

let user: { address?: { street?: string } } = {};

console.log(user.address?.street); // 输出: undefined

let user = {
  name: "Alice",
  greet: () => "Hello"
};

console.log(user.greet?.()); // 输出: "Hello"

let anotherUser = { name: "Bob" };
console.log(anotherUser.greet?.()); // 输出: undefined

模块

程序可划分为多组编译单元或模块。

导出

使用关键字export导出顶层的声明。

export class Point {
  x: number = 0
  y: number = 0
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
}
export let Origin = new Point(0, 0);
export function Distance(p1: Point, p2: Point): number {
  return Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}

导入

静态导入

import * as Utils from './utils'
Utils.X // 表示来自Utils的X
Utils.Y // 表示来自Utils的Y

import { X, Y } from './utils'
X // 表示来自utils的X
Y // 表示来自utils的Y

import { X as Z, Y } from './utils'
Z // 表示来自Utils的X
Y // 表示来自Utils的Y
X // 编译时错误:'X'不可见

动态导入

用于实现根据条件导入模块或者按需导入模块。

// say.ts
export function hi() {
  console.log('Hello');
}
export function bye() {
  console.log('Bye');
}
// index.ets
async function test() {
  let ns = await import('./say');
  let hi = ns.hi;
  let bye = ns.bye;
  hi();
  bye();
}

导入HarmonyOS SDK的开放能力

导入接口模块:

import UIAbility from '@ohos.app.ability.UIAbility';

从HarmonyOS NEXT Developer Preview 1版本开始引入Kit概念。SDK对同一个Kit下的接口模块进行了封装,开发者在示例代码中可通过导入Kit的方式来使用Kit所包含的接口能力。

其中,Kit封装的接口模块可查看SDK目录下Kit子目录中各Kit的定义。

通过导入Kit方式使用开放能力有三种方式:

  • 方式一:导入Kit下单个模块的接口能力。例如:

    import { UIAbility } from '@kit.AbilityKit';
    // AbilityKit - 程序框架服务
    // UIAbility - 包含UI界面的应用组件
  • 方式二:导入Kit下多个模块的接口能力。例如:

    import { UIAbility, Ability, Context } from '@kit.AbilityKit';
    // Ability - UIAbility和ExtensionAbility的基类,
    // 提供系统配置更新回调和系统内存调整回调
  • 方式三:导入Kit包含的所有模块的接口能力。例如:

    import * as module from '@kit.AbilityKit';

    其中,“module”为别名,可自定义,然后通过该名称调用模块的接口。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部