注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下
如果大家觉得博主文章写的好的话,可以点下关注,博主会一直更新鸿蒙next相关知识
专栏地址: https://blog.csdn.net/qq_56760790/category_12794123.html
目录
1. ArkTS基本介绍
2. ArkTS语法
2.1 变量声明
2.2 常量声明
2.3 自动类型推断
2.4 联合类型
2.5 枚举类型
2.6 数组
2.7 函数
2.7.1 可选参数
2.7.2 Rest参数
2.7.3 返回类型
2.7.4 箭头函数(又名Lambda函数)
2.8 类
2.9 接口
2.10 对象
2.10.1 接口类型
2.10.2 类类型
2.11 泛型类型和函数
2.11.1 泛型类和接口
2.11.2 泛型约束
2.11.3 泛型函数
2.12 语句
2.12.1 if语句
2.12.2 Switch语句
2.12.3 条件表达式
2.12.4 For语句
2.12.5 For-of语句
2.12.6 While语句
2.12.7 Do-while语句
2.12.8 Break语句
2.12.9 Continue语句
2.13 模块
2.13.1 导出
2.13.2 导入
3. ArkTS组件结构
3.1 基于struct实现自定义组件
3.2 Component修饰符
3.3 Build函数
3.4 entry修饰符
3.5 组件复用
4. 视频学习链接
1. ArkTS基本介绍
ArkTS是HarmonyOS优选的主力应用开发语言。
ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,保持了TS的基本风格,同时通过规范定义强化开发期静态检查和分析,提升程序执行稳定性和性能。
从API version 10开始,ArkTS进一步通过规范强化静态检查和分析,对比标准TS的差异可以参考从TypeScript到ArkTS的适配规则:
- 强制使用静态类型:静态类型是ArkTS最重要的特性之一。如果使用静态类型,那么程序中变量的类型就是确定的。同时,由于所有类型在程序实际运行前都是已知的,编译器可以验证代码的正确性,从而减少运行时的类型检查,有助于性能提升。
- 禁止在运行时改变对象布局:为实现最大性能,ArkTS要求在程序执行期间不能更改对象布局。
- 限制运算符语义:为获得更好的性能并鼓励开发者编写更清晰的代码,ArkTS限制了一些运算符的语义。比如,一元加法运算符只能作用于数字,不能用于其他类型的变量。
- 不支持Structural typing:对Structural typing的支持需要在语言、编译器和运行时进行大量的考虑和仔细的实现,当前ArkTS不支持该特性。根据实际场景的需求和反馈,我们后续会重新考虑。
ArkTS它是纯新的一门语言,它不是前端也不是TypeScript,它是TS的超集
- ArkTS的特性-扩展能力
- 基本语法
-
- 定义声明式UI、自定义组件、动态扩展UI元素;
- 提供ArkUI系统组件,提供组件事件、方法、属性;
- 共同构成 UI 开发主体
- 状态管理
-
- 组件状态、组件数据共享、应用数据共享、设备共享;
- 渲染控制
-
- 条件渲染、循环渲染、数据懒加载;
ArkTS以声明方式组合和扩展组件来描述应用程序的UI,同时还提供了基本的属性、事件和子组件配置方法,帮助开发者实现应用交互逻辑。
- 命令式UI- document.createElement("div")- <div>
- 声明式UI
ArkTS提供了标准内置对象,例如Array、Map、TypedArray、Math等,供开发者直接使用。另外,ArkTS也提供了语言基础类库,为应用开发者提供常用的基础能力,主要包含能力如下图所示。
2. ArkTS语法
ArkTS通过声明引入变量、常量、函数和类型。
2.1 变量声明
以关键字let开头的声明引入变量,该变量在程序执行期间可以具有不同的值。
let hi: string = 'hello';
hi = 'hello, world';
2.2 常量声明
以关键字const开头的声明引入只读常量,该常量只能被赋值一次。
const hello: string = 'hello';
对常量重新赋值会造成编译时错误。
变量、常量的命名规则:
- 只能包含数字、字母、下划线、$,不能以数字开头
- 不能使用内置关键字或保留字(比如let const)
- 严格区分大小写
2.3 自动类型推断
由于ArkTS是一种静态类型语言,所有数据的类型都必须在编译时确定。
但是,如果一个变量或常量的声明包含了初始值,那么开发者就不需要显式指定其类型。ArkTS规范中列举了所有允许自动推断类型的场景。
以下示例中,两条声明语句都是有效的,两个变量都是string类型:
let hi1: string = 'hello';
let hi2 = 'hello, world';
2.4 联合类型
联合类型是一种灵活的数据类型,它修饰的变量可以存储不同类型的数据;
语法:
let 变量:类型1|类型2|类型3 =值
let name:string|number;
name=1
name='东林'
2.5 枚举类型
枚举类型是一种特殊的数据类型,约定变量只能在一组数据范围内选择值
语法:
enum 枚举名{
常量1=值,
常量2=值
}
enum Color{Red='#ff0f29',Green='#30b30e'
}
// 使用枚举
let color:Color=Color.Red
2.6 数组
ArkTS基本数据类型(string、number、boolean等,语法跟ts差不多,大家可以在东林录制的视频前置课里面学习)
数组,是一个容器,可以存储多个数据;
语法:
let 数组名:类型[]=[数据1,数据2,....]
let names:string[]=['小头','东林']
注意:数组指定的类型和存储的数据类型必须要一致,否则会报错
数组中存储的每个数据,都有自己的编号,编号从0开始(索引)
联合类型:
let names:(string|number)[]=[1,2,'小头']
2.7 函数
函数:是可以被重复使用的代码块
定义函数:
function 函数名()
{
}
调用函数:
函数名()
函数的完整用法
function add(x: string, y: string): string {let z: string = `${x} ${y}`;return z;
}
2.7.1 可选参数
可选参数的格式可为name?: Type
function hello(name?: string) {if (name == undefined) {console.log('Hello!');} else {console.log(`Hello, ${name}!`);}
}
可选参数的另一种形式为设置的参数默认值。如果在函数调用中这个参数被省略了,则会使用此参数的默认值作为实参。
function multiply(n: number, coeff: number = 2): number {return n * coeff;
}
multiply(2); // 返回2*2
multiply(2, 3); // 返回2*3
2.7.2 Rest参数
函数的最后一个参数可以是rest参数。使用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
2.7.3 返回类型
如果可以从函数体内推断出函数返回类型,则可在函数声明中省略标注返回类型。
// 显式指定返回类型
function foo(): string { return 'foo'; }// 推断返回类型为string
function goo() { return 'goo'; }
不需要返回值的函数的返回类型可以显式指定为void或省略标注。这类函数不需要返回语句。
2.7.4 箭头函数(又名Lambda函数)
箭头函数是比普通函数更简洁的一种函数写法
函数可以定义为箭头函数,例如:
let sum = (x: number, y: number): number => {return x + y;
}
2.8 类
类声明引入一个新类型,并定义其字段、方法和构造函数。
在以下示例中,定义了Person类,该类具有字段name和surname、构造函数和方法fullName:
class Person {name: string = ''surname: string = ''constructor (n: string, sn: string) {this.name = n;this.surname = sn;}fullName(): string {return this.name + ' ' + this.surname;}
}
定义类后,可以使用关键字new创建实例:
let p = new Person('John', 'Smith');
console.log(p.fullName());
2.9 接口
接口声明引入新类型。接口是定义代码协定的常见方式。
任何一个类的实例只要实现了特定接口,就可以通过该接口实现多态。
接口通常包含属性和方法的声明
interface Style {color: string // 属性
}
interface AreaSize {calculateAreaSize(): number // 方法的声明someMethod(): void; // 方法的声明
}
实现接口的类示例:
// 接口:
interface AreaSize {calculateAreaSize(): number // 方法的声明someMethod(): void; // 方法的声明
}// 实现:
class RectangleSize implements AreaSize {private width: number = 0private height: number = 0someMethod(): void {console.log('someMethod called');}calculateAreaSize(): number {this.someMethod(); // 调用另一个方法并返回结果return this.width * this.height;}
}
2.10 对象
语法:let 对象名称:对应结构类型=值
2.10.1 接口类型
interface People{name:stringage:number
}let pick:People={name:'pick',age:1
}
2.10.2 类类型
class People{name:string=''age:number=0
}let pick:People={name:'pick',age:1
}
2.11 泛型类型和函数
泛型类型和函数允许创建的代码在各种类型上运行,而不仅支持单一类型。
2.11.1 泛型类和接口
类和接口可以定义为泛型,将参数添加到类型定义中,如以下示例中的类型参数Element:
class CustomStack<Element> {public push(e: Element):void {// ...}
}
要使用类型CustomStack,必须为每个类型参数指定类型实参:
let s = new CustomStack<string>();
s.push('hello');
2.11.2 泛型约束
泛型类型的类型参数可以被限制只能取某些特定的值。例如,MyHashMap<Key, Value>这个类中的Key类型参数必须具有hash方法。
interface Hashable {hash(): number
}
class MyHashMap<Key extends Hashable, Value> {public set(k: Key, v: Value) {let h = k.hash();// ...其他代码...}
}
在上面的例子中,Key类型扩展了Hashable,Hashable接口的所有方法都可以为key调用。
2.11.3 泛型函数
使用泛型函数可编写更通用的代码。比如返回数组最后一个元素的函数:
function last(x: number[]): number {return x[x.length - 1];
}
last([1, 2, 3]); // 3
如果需要为任何数组定义相同的函数,使用类型参数将该函数定义为泛型:
function last<T>(x: T[]): T {return x[x.length - 1];
}
2.12 语句
2.12.1 if语句
if语句用于需要根据逻辑条件执行不同语句的场景。当逻辑条件为真时,执行对应的一组语句,否则执行另一组语句(如果有的话)。
else部分也可能包含if语句。
if语句如下所示:
if (condition1) {// 语句1
} else if (condition2) {// 语句2
} else {// else语句
}
条件表达式可以是任何类型。但是对于boolean以外的类型,会进行隐式类型转换:
let s1 = 'Hello';
if (s1) {console.log(s1); // 打印“Hello”
}let s2 = 'World';
if (s2.length != 0) {console.log(s2); // 打印“World”
}
2.12.2 Switch语句
使用switch语句来执行与switch表达式值匹配的代码块。
switch语句如下所示:
switch (expression) {case label1: // 如果label1匹配,则执行// ...// 语句1// ...break; // 可省略case label2:case label3: // 如果label2或label3匹配,则执行// ...// 语句23// ...break; // 可省略default:// 默认语句
}
2.12.3 条件表达式
条件表达式由第一个表达式的布尔值来决定返回其它两个表达式中的哪一个。
condition ? expression1 : expression2
如果condition的为真值(转换后为true的值),则使用expression1作为该表达式的结果;否则,使用expression2。
2.12.4 For语句
for语句会被重复执行,直到循环退出语句值为false。
for ([init]; [condition]; [update]) {statements
}
2.12.5 For-of语句
使用for-of语句可遍历数组或字符串。示例如下:
for (forVar of expression) {statements
}
for (let ch of 'a string object') {/* process ch */
}
2.12.6 While语句
只要condition为真值(转换后为true的值),while语句就会执行statements语句。示例如下:
while (condition) {statements
}
let n = 0;
let x = 0;
while (n < 3) {n++;x += n;
}
2.12.7 Do-while语句
如果condition的值为真值(转换后为true的值),那么statements语句会重复执行。示例如下:
do {statements
} while (condition)
let i = 0;
do {i += 1;
} while (i < 10)
2.12.8 Break语句
使用break语句可以终止循环语句或switch。
let x = 0;
while (true) {x++;if (x > 5) {break;}
}
2.12.9 Continue语句
continue语句会停止当前循环迭代的执行,并将控制传递给下一个迭代。
let sum = 0;
for (let x = 0; x < 100; x++) {if (x % 2 == 0) {continue}sum += x;
}
2.13 模块
程序可划分为多组编译单元或模块。
每个模块都有其自己的作用域,即,在模块中创建的任何声明(变量、函数、类等)在该模块之外都不可见,除非它们被显式导出。
与此相对,从另一个模块导出的变量、函数、类、接口等必须首先导入到模块中。
2.13.1 导出
可以使用关键字export导出顶层的声明。
未导出的声明名称被视为私有名称,只能在声明该名称的模块中使用。
注意:通过export方式导出,在导入时要加{}。
export class Point {x: number = 0y: number = 0constructor(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));
}
2.13.2 导入
导入声明用于导入从其他模块导出的实体,并在当前模块中提供其绑定。导入声明由两部分组成:
- 导入路径,用于指定导入的模块;
- 导入绑定,用于定义导入的模块中的可用实体集和使用形式(限定或不限定使用)。
导入绑定可以有几种形式。
假设模块具有路径“./utils”和导出实体“X”和“Y”。
导入绑定* as A表示绑定名称“A”,通过A.name可访问从导入路径指定的模块导出的所有实体:
import * as Utils from './utils'
Utils.X // 表示来自Utils的X
Utils.Y // 表示来自Utils的Y
导入绑定{ ident1, ..., identN }表示将导出的实体与指定名称绑定,该名称可以用作简单名称:
import { X, Y } from './utils'
X // 表示来自utils的X
Y // 表示来自utils的Y
如果标识符列表定义了ident as alias,则实体ident将绑定在名称alias下:
import { X as Z, Y } from './utils'
Z // 表示来自Utils的X
Y // 表示来自Utils的Y
X // 编译时错误:'X'不可见
3. ArkTS组件结构
ArkTS的基本组成
说明
自定义变量不能与基础通用属性/事件名重复。
ArkTS通过装饰器 @Component
和 @Entry
装饰 struct
关键字声明的数据结构,构成一个自定义组件。
自定义组件中提供了一个 build
函数,开发者需在该函数内以链式调用的方式进行基本的 UI 描述,UI 描述的方法请参考 UI 描述规范。
3.1 基于struct实现自定义组件
要想实现一段UI的描述,必须使用struct关键字来声明- 注意不能有继承关系-组件名不能和系统组件名重名
语法: struct 组件名 {}
@Componentstruct Index {}
struct关键字声明的UI描述-必须被@Component修饰
3.2 Component修饰符
Component装饰器只能修饰struct关键字声明的结构,被修饰后的struct具备组件的描述(渲染)能力
3.3 Build函数
用于定义组件的UI描述,一个struct结构必须实现build函数
@Componentstruct MyComponent {build() {}}
3.4 entry修饰符
entry将自定义组件定义为UI页面的入口,也就是我们原来前端常说的一个页面,最多可以使用entry装饰一个自定义组件(在一个ets文件中)-如下面的代码就是不被允许的
@Entry@Componentstruct Index {build() {}}
@Entry@Componentstruct Index2 {build() {}}
entry修饰的组件,最终会被注册,具体文件位置-main/resources/base/profile/main_pages.json
- 自动注册-新建组件时,采用新建Page的方式
- 手动注册-新建一个ets文件,自己在main_pages.json中手动添加路径
3.5 组件复用
在很多情况下,由于业务的复杂度,我们经常会将一个大的业务拆成若干个组件,进行组装,这里我们非常灵活的复用组件,比如
- 我们可以把上图抽象成三个组件- Header- Main- Footer
import Header from '../pages/Header';
import Main from '../pages/Main';
import Foot from '../pages/Foot';@Entry
@Component
struct Demo {build() {Column() {Header().backgroundColor(Color.Pink)Main().backgroundColor(Color.Green)Foot().backgroundColor(Color.Red)}.height('100%').width('100%')}
}
@Componentexport default struct Header {build() {Row() {Text('头部')}.width('100%').height(60).justifyContent(FlexAlign.Center)}}
@Componentexport default struct Main{build() {Row(){Text('主体')}.width('100%').height('80%').justifyContent(FlexAlign.Center)}}
@Componentexport default struct Foot{build() {Row(){Text('底部')}.width('100%').height('10%').justifyContent(FlexAlign.Center)}}
总结:
- 一个UI描述必须使用struct来声明,不能继承
- struct必须被Component或者CustomDialog修饰
- struct必须实现build方法,build方法可以没有元素,但是有的话有且只有一个可容纳子组件的容器组件(entry修饰的组件)
- entry修饰符表示该组件是页面级组件,一个文件中只允许修饰一个struct组件
- 采用分拆组件的形式可以有效解解耦我们的业务
4. 视频学习链接
全网首发鸿蒙NEXT星河版零基础入门到实战,2024年最新版,企业级开发!视频陆续更新中!_哔哩哔哩_bilibili