面向 HarmonyOS 应用开发的 ArkTS 语言从入门到实战,涵盖完整语法 + 声明式 UI + 综合案例。
文章目录
- [1. ArkTS 是什么](#1. ArkTS 是什么)
- [2. 开发环境与第一个程序](#2. 开发环境与第一个程序)
- [3. 变量与数据类型](#3. 变量与数据类型)
- [4. 运算符与表达式](#4. 运算符与表达式)
- [5. 字符串](#5. 字符串)
- [6. 条件与循环](#6. 条件与循环)
- [7. 函数](#7. 函数)
- [8. 数组与集合](#8. 数组与集合)
- [9. 对象与接口](#9. 对象与接口)
- [10. 类与面向对象](#10. 类与面向对象)
- [11. 泛型](#11. 泛型)
- [12. 声明式 UI 基础(ArkUI)](#12. 声明式 UI 基础(ArkUI))
- [13. 状态管理](#13. 状态管理)
- [14. 事件处理与常用组件](#14. 事件处理与常用组件)
- [15. 综合案例:TodoList 待办应用](#15. 综合案例:TodoList 待办应用)
- 附录:学习路线建议
1. ArkTS 是什么
ArkTS 是华为专为 HarmonyOS 开发的一门语言,它在 TypeScript(TS) 的基础上做了严格化和扩展,核心特点:
- 静态类型强约束 :不允许
any随便乱飞,编译期就能发现类型错误,适合大型工程。 - 声明式 UI 范式:用类似"描述界面长什么样"的方式写 UI,数据变了界面自动刷新。
- 响应式状态管理 :通过
@State、@Link等装饰器,把数据和界面绑定起来。 - 禁止动态特性 :不支持
eval()、不允许随意delete属性、不允许用索引访问任意字段,目的是提升性能和稳定性。
一句话理解:ArkTS = 严格版 TypeScript + 鸿蒙专属的 UI 框架。如果你学过 TS,迁移非常快;如果没学过 TS,按本教程走也没问题。
2. 开发环境与第一个程序
2.1 环境准备
- 安装 DevEco Studio(华为官方 IDE,类似 Android Studio)。
- 创建新项目时选择 Empty Ability ,语言选 ArkTS。
- 项目核心代码在
entry/src/main/ets/目录下。
2.2 第一个 Hello World
打开 entry/src/main/ets/pages/Index.ets,默认代码如下:
typescript
@Entry
@Component
struct Index {
build() {
Column() {
Text('Hello World')
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
逐行解释:
| 代码 | 作用 |
|---|---|
@Entry |
标记这是页面入口组件(一个页面只能有一个) |
@Component |
标记这是一个 UI 组件,可以被复用 |
struct Index |
定义一个结构体(ArkTS 用 struct 写组件) |
build() |
必须实现的方法,描述这个组件长什么样 |
Column() |
线性布局,子元素竖向排列 |
Text('Hello World') |
文本组件 |
.fontSize(30) |
链式调用设置样式 |
点击运行按钮,模拟器上就能看到居中的 "Hello World"。
3. 变量与数据类型
3.1 声明变量
ArkTS 只允许用 let 和 const ,禁止使用 var。
typescript
let name: string = '小明' // 可变变量
const PI: number = 3.14159 // 常量,不能重新赋值
let age = 20 // 类型自动推导为 number
let:变量值可以改。const:常量,声明时必须赋值,之后不能改。- 推荐:默认用
const,确定要改才用let。
3.2 基本数据类型
| 类型 | 说明 | 示例 |
|---|---|---|
number |
数字(整数和小数都是它) | 42、3.14、-7 |
string |
字符串 | '你好'、"hello" |
boolean |
布尔值 | true、false |
null |
空值 | null |
undefined |
未定义 | undefined |
void |
函数无返回值 | function f(): void {} |
3.3 类型注解
typescript
let score: number = 95
let username: string = 'zhangsan'
let isPass: boolean = true
类型注解是可选的------编译器会自动推导,但写上更清晰,大型项目建议显式标注。
3.4 联合类型
一个变量可以是多种类型之一:
typescript
let id: number | string
id = 100 // OK
id = 'A001' // OK
// id = true // 报错,boolean 不在联合类型里
3.5 字面量类型
限定变量只能取某个具体值:
typescript
let direction: 'up' | 'down' | 'left' | 'right'
direction = 'up' // OK
// direction = 'back' // 报错
4. 运算符与表达式
4.1 算术运算符
typescript
let a: number = 10
let b: number = 3
a + b // 13
a - b // 7
a * b // 30
a / b // 3.333...
a % b // 1(取余)
a ** b // 1000(幂运算)
4.2 比较运算符
typescript
5 > 3 // true
5 >= 5 // true
5 < 3 // false
5 == '5' // false(ArkTS 严格相等,类型不同直接 false)
5 === 5 // true(推荐用 === 和 !==)
5 != '5' // true
5 !== 5 // false
注意 :ArkTS 没有
==的隐式转换,推荐始终用===和!==。
4.3 逻辑运算符
typescript
true && false // false(与)
true || false // true(或)
!true // false(非)
4.4 赋值运算符
typescript
let x: number = 10
x += 5 // x = 15
x -= 3 // x = 12
x *= 2 // x = 24
x /= 4 // x = 6
4.5 三元运算符
typescript
let age: number = 20
let result: string = age >= 18 ? '成年' : '未成年'
5. 字符串
5.1 多种写法
typescript
let s1: string = '单引号'
let s2: string = "双引号"
let s3: string = `模板字符串`
5.2 模板字符串(重点)
用反引号 ````` 包裹,可以嵌入变量:
typescript
let name: string = '小红'
let age: number = 18
let msg: string = `我叫${name},今年${age}岁`
// 我叫小红,今年18岁
还支持换行:
typescript
let poem: string = `床前明月光,
疑是地上霜。`
5.3 常用方法
typescript
let str: string = 'Hello ArkTS'
str.length // 11
str.toUpperCase() // 'HELLO ARKTS'
str.toLowerCase() // 'hello arkts'
str.indexOf('Ark') // 6
str.substring(6, 11) // 'ArkTS'
str.split(' ') // ['Hello', 'ArkTS']
str.replace('Ark', 'Harmony') // 'Hello HarmonyTS'
str.trim() // 去除首尾空格
6. 条件与循环
6.1 if / else
typescript
let score: number = 85
if (score >= 90) {
console.log('优秀')
} else if (score >= 80) {
console.log('良好')
} else if (score >= 60) {
console.log('及格')
} else {
console.log('不及格')
}
6.2 switch
typescript
let day: number = 3
switch (day) {
case 1:
console.log('周一')
break
case 2:
console.log('周二')
break
case 3:
console.log('周三')
break
default:
console.log('其他')
}
6.3 for 循环
typescript
// 经典 for
for (let i: number = 0; i < 5; i++) {
console.log(i) // 0 1 2 3 4
}
6.4 for...of(遍历数组)
typescript
let fruits: string[] = ['苹果', '香蕉', '橙子']
for (let fruit of fruits) {
console.log(fruit)
}
6.5 while 循环
typescript
let count: number = 3
while (count > 0) {
console.log(count)
count--
}
7. 函数
7.1 函数声明
typescript
function add(a: number, b: number): number {
return a + b
}
let sum: number = add(3, 5) // 8
括号里 a: number 是参数类型,: number 在括号后面是返回值类型。
7.2 箭头函数(常用)
typescript
const multiply = (a: number, b: number): number => {
return a * b
}
// 单行可以省略 return 和大括号
const square = (x: number): number => x * x
7.3 参数默认值
typescript
function greet(name: string, greeting: string = '你好'): string {
return `${greeting},${name}`
}
greet('小明') // '你好,小明'
greet('小红', '早上好') // '早上好,小红'
7.4 可选参数
用 ? 标记可选参数:
typescript
function buildName(first: string, last?: string): string {
if (last) {
return `${first} ${last}`
}
return first
}
buildName('张') // '张'
buildName('张', '三') // '张 三'
7.5 无返回值
typescript
function logMessage(msg: string): void {
console.log(msg)
}
8. 数组与集合
8.1 数组声明与初始化
typescript
let nums: number[] = [1, 2, 3, 4, 5]
let names: Array<string> = ['Tom', 'Jerry']
let empty: number[] = []
8.2 常用操作
typescript
let arr: number[] = [10, 20, 30]
arr.push(40) // 末尾添加:[10,20,30,40]
arr.pop() // 末尾删除:返回 40
arr.unshift(5) // 开头添加:[5,10,20,30]
arr.shift() // 开头删除:返回 5
arr.length // 长度
arr[0] // 访问第一个元素
arr.indexOf(20) // 查找索引
8.3 数组遍历方法(重点)
typescript
let numbers: number[] = [1, 2, 3, 4, 5]
// forEach:遍历
numbers.forEach((n: number) => {
console.log(n)
})
// map:映射成新数组
let doubled: number[] = numbers.map((n: number): number => n * 2)
// [2, 4, 6, 8, 10]
// filter:过滤
let evens: number[] = numbers.filter((n: number): boolean => n % 2 === 0)
// [2, 4]
// reduce:汇总
let total: number = numbers.reduce((sum: number, n: number): number => sum + n, 0)
// 15
// find:查找第一个满足条件的
let firstBig: number | undefined = numbers.find((n: number): boolean => n > 3)
// 4
8.4 Set(不重复集合)
typescript
let set: Set<number> = new Set([1, 2, 2, 3, 3, 3])
// Set {1, 2, 3}
set.add(4)
set.has(2) // true
set.delete(1)
set.size // 3
8.5 Map(键值对)
typescript
let map: Map<string, number> = new Map()
map.set('语文', 90)
map.set('数学', 95)
map.get('语文') // 90
map.has('数学') // true
map.delete('语文')
map.size // 1
九、对象与接口
9.1 接口(interface)------ ArkTS 核心
接口用来描述对象的结构:
typescript
interface User {
name: string
age: number
email?: string // 可选属性
}
let user: User = {
name: '小明',
age: 20,
email: 'xiao@test.com'
}
console.log(user.name) // 小明
接口是 ArkTS 中最常用的类型定义方式,用来规范数据结构,配合 UI 组件传参非常方便。
9.2 type 别名
typescript
type Point = {
x: number
y: number
}
let p: Point = { x: 10, y: 20 }
接口和 type 大部分场景可互换,推荐对象结构用 interface,联合类型/别名用 type。
9.3 接口继承
typescript
interface Animal {
name: string
}
interface Dog extends Animal {
breed: string
}
let myDog: Dog = {
name: '旺财',
breed: '金毛'
}
十、类与面向对象
10.1 定义类
typescript
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
sayHello(): void {
console.log(`你好,我叫${this.name},今年${this.age}岁`)
}
}
let p: Person = new Person('小明', 20)
p.sayHello() // 你好,我叫小明,今年20岁
10.2 访问修饰符
| 修饰符 | 说明 |
|---|---|
public |
公开(默认),内外都能访问 |
private |
私有,只有类内部能访问 |
protected |
保护,类内部和子类能访问 |
typescript
class Account {
public owner: string
private balance: number
constructor(owner: string, balance: number) {
this.owner = owner
this.balance = balance
}
deposit(amount: number): void {
this.balance += amount
}
getBalance(): number {
return this.balance
}
}
let acc: Account = new Account('张三', 1000)
acc.deposit(500)
console.log(acc.getBalance()) // 1500
// console.log(acc.balance) // 报错,private 不能外部访问
10.3 继承
typescript
class Student extends Person {
school: string
constructor(name: string, age: number, school: string) {
super(name, age) // 调用父类构造函数
this.school = school
}
study(): void {
console.log(`${this.name}在${this.school}上学`)
}
}
let s: Student = new Student('小红', 19, '西安电子科技大学')
s.sayHello() // 继承自父类
s.study() // 自己的方法
10.4 static 静态成员
typescript
class Calculator {
static PI: number = 3.14159
static circleArea(radius: number): number {
return Calculator.PI * radius * radius
}
}
console.log(Calculator.circleArea(5)) // 78.53975
10.5 getter / setter
typescript
class Rectangle {
private _width: number = 0
private _height: number = 0
set width(w: number) {
if (w > 0) {
this._width = w
}
}
get width(): number {
return this._width
}
get area(): number {
return this._width * this._height
}
}
十一、泛型
泛型就是"类型的参数",让函数/类可以适配多种类型而不丢失类型检查。
11.1 泛型函数
typescript
function identity<T>(arg: T): T {
return arg
}
let n: number = identity<number>(42)
let str: string = identity<string>('hello')
11.2 泛型接口
typescript
interface Result<T> {
code: number
data: T
message: string
}
let r1: Result<string> = { code: 200, data: '成功', message: 'OK' }
let r2: Result<number[]> = { code: 200, data: [1, 2, 3], message: 'OK' }
11.3 泛型类
typescript
class Stack<T> {
private items: T[] = []
push(item: T): void {
this.items.push(item)
}
pop(): T | undefined {
return this.items.pop()
}
}
let numStack: Stack<number> = new Stack<number>()
numStack.push(1)
numStack.push(2)
十二、声明式 UI 基础(ArkUI)
ArkTS 的核心是 ArkUI 声明式开发范式。界面由组件组合而成。
12.1 核心概念
- 组件(Component) :UI 的基本单元,如
Text、Button、Image。 - 布局容器 :控制子组件如何排列,如
Column、Row、Stack、Flex。 - build() 函数:描述组件 UI 的入口。
12.2 常用基础组件
typescript
@Entry
@Component
struct BasicsPage {
build() {
Column({ space: 10 }) {
// 文本
Text('你好,ArkTS')
.fontSize(24)
.fontColor('#333333')
// 按钮
Button('点击我')
.type(ButtonType.Capsule)
.width(150)
.height(40)
// 图片
Image('https://example.com/icon.png')
.width(60)
.height(60)
// 输入框
TextInput({ placeholder: '请输入内容' })
.width('90%')
.height(45)
}
.width('100%')
.padding(16)
}
}
12.3 布局容器
Column(竖向排列)
typescript
Column({ space: 12 }) {
Text('第一行')
Text('第二行')
Text('第三行')
}
.width('100%')
.alignItems(HorizontalAlign.Center) // 子元素水平居中
Row(横向排列)
typescript
Row({ space: 16 }) {
Text('左')
Text('中')
Text('右')
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly) // 子元素均匀分布
Stack(层叠布局)
typescript
Stack({ alignContent: Alignment.BottomCenter }) {
Image('bg.jpg').width(200).height(200)
Text('覆盖在上面的文字')
.fontColor(Color.White)
}
12.4 通用样式属性
typescript
Text('样式演示')
.width(200)
.height(50)
.backgroundColor('#F0F0F0')
.borderRadius(8)
.padding(10)
.margin({ top: 10, bottom: 10 })
.textAlign(TextAlign.Center)
十三、状态管理
状态管理是 ArkTS 声明式 UI 的灵魂:数据变了,界面自动刷新。
13.1 @State(组件内状态)
@State 修饰的变量变化时,UI 自动重新渲染:
typescript
@Entry
@Component
struct CounterPage {
@State count: number = 0 // 状态变量
build() {
Column({ space: 20 }) {
Text(`当前计数:${this.count}`)
.fontSize(28)
Button('+1')
.onClick(() => {
this.count++ // 修改状态 → 界面自动刷新
})
Button('重置')
.onClick(() => {
this.count = 0
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
关键点 :只要
this.count变了,Text组件就会自动重新渲染,你不需要手动操作 DOM。
13.2 @Prop(父传子,单向)
父组件传给子组件的数据,子组件只读:
typescript
// 子组件
@Component
struct ChildText {
@Prop message: string // 接收父组件传入的值
build() {
Text(this.message).fontSize(20)
}
}
// 父组件
@Entry
@Component
struct ParentPage {
@State parentMsg: string = '来自爸爸的消息'
build() {
Column() {
ChildText({ message: this.parentMsg })
}
}
}
13.3 @Link(父子双向绑定)
父子组件共享同一份数据,任意一方修改都同步:
typescript
@Component
struct CounterChild {
@Link count: number // 双向绑定
build() {
Button('子组件 +1')
.onClick(() => {
this.count++ // 修改会同步回父组件
})
}
}
@Entry
@Component
struct CounterParent {
@State count: number = 0
build() {
Column({ space: 20 }) {
Text(`父组件计数:${this.count}`).fontSize(24)
CounterChild({ count: $count }) // 注意 $ 符号表示双向绑定
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
}
}
13.4 @Builder(自定义 UI 片段)
把重复的 UI 抽成模板:
typescript
@Entry
@Component
struct BuilderPage {
@State title: string = '卡片标题'
@Builder
card(title: string, content: string) {
Column() {
Text(title).fontSize(18).fontWeight(FontWeight.Bold)
Text(content).fontSize(14).fontColor('#666')
}
.width('90%')
.padding(16)
.backgroundColor(Color.White)
.borderRadius(12)
}
build() {
Column({ space: 12 }) {
this.card('通知', '你有一条新消息')
this.card('提醒', '记得喝水')
}
.width('100%')
.backgroundColor('#F5F5F5')
.padding(16)
}
}
十四、事件处理与常用组件
14.1 点击事件
typescript
Button('按钮')
.onClick(() => {
console.log('按钮被点击了')
})
14.2 输入框与状态绑定
typescript
@Entry
@Component
struct InputPage {
@State inputText: string = ''
build() {
Column({ space: 16 }) {
TextInput({ text: this.inputText, placeholder: '请输入' })
.width('90%')
.height(45)
.onChange((value: string) => {
this.inputText = value // 输入内容实时同步到状态
})
Text(`你输入了:${this.inputText}`)
.fontSize(18)
}
.width('100%')
.padding(16)
}
}
14.3 List 列表(高频使用)
typescript
@Entry
@Component
struct ListPage {
@State todos: string[] = ['学习 ArkTS', '写作业', '健身', '买水果']
build() {
Column() {
Text('待办列表').fontSize(22).fontWeight(FontWeight.Bold)
List({ space: 10 }) {
ForEach(this.todos, (item: string, index: number) => {
ListItem() {
Text(`${index + 1}. ${item}`)
.fontSize(18)
.padding(12)
.width('100%')
.backgroundColor(Color.White)
.borderRadius(8)
}
})
}
.width('90%')
.layoutWeight(1)
}
.width('100%')
.height('100%')
.padding(16)
.backgroundColor('#F5F5F5')
}
}
ForEach是列表渲染的核心,类似 React 的 map,根据数组生成重复组件。
十五、综合案例:TodoList 待办应用
把前面学的所有知识整合起来,做一个完整的待办事项应用:支持添加、完成、删除任务。
typescript
// 数据模型
interface Todo {
id: number
text: string
completed: boolean
}
@Entry
@Component
struct TodoListApp {
// 状态
@State newTask: string = ''
@State todoList: Todo[] = [
{ id: 1, text: '学习 ArkTS 基础语法', completed: true },
{ id: 2, text: '完成布局练习', completed: false },
{ id: 3, text: '写综合案例', completed: false }
]
private nextId: number = 4
// 统计完成数
get completedCount(): number {
return this.todoList.filter((t: Todo): boolean => t.completed).length
}
// 添加任务
addTask(): void {
if (this.newTask.trim().length === 0) {
return
}
let task: Todo = {
id: this.nextId++,
text: this.newTask.trim(),
completed: false
}
this.todoList.push(task)
this.newTask = '' // 清空输入框
}
// 切换完成状态
toggleTask(id: number): void {
this.todoList = this.todoList.map((item: Todo): Todo => {
if (item.id === id) {
return {
id: item.id,
text: item.text,
completed: !item.completed
}
}
return item
})
}
// 删除任务
deleteTask(id: number): void {
this.todoList = this.todoList.filter((item: Todo): boolean => item.id !== id)
}
build() {
Column() {
// 标题
Text('我的待办')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#333333')
.margin({ top: 20, bottom: 10 })
// 统计
Text(`共 ${this.todoList.length} 项,已完成 ${this.todoList.filter((t: Todo): boolean => t.completed).length} 项`)
.fontSize(14)
.fontColor('#888888')
.margin({ bottom: 16 })
// 输入区域
Row({ space: 10 }) {
TextInput({ text: this.newTask, placeholder: '输入新任务...' })
.layoutWeight(1)
.height(45)
.backgroundColor(Color.White)
.borderRadius(8)
.onChange((value: string) => {
this.newTask = value
})
.onSubmit(() => {
this.addTask()
})
Button('添加')
.height(45)
.onClick(() => {
this.addTask()
})
}
.width('90%')
.margin({ bottom: 16 })
// 任务列表
List({ space: 10 }) {
ForEach(this.todoList, (item: Todo) => {
ListItem() {
Row() {
// 完成标记圆圈
Text(item.completed ? '✓' : ' ')
.fontSize(16)
.fontColor(Color.White)
.width(26)
.height(26)
.textAlign(TextAlign.Center)
.borderRadius(13)
.backgroundColor(item.completed ? '#4CAF50' : '#CCCCCC')
.onClick(() => {
this.toggleTask(item.id)
})
// 任务文字
Text(item.text)
.fontSize(16)
.layoutWeight(1)
.margin({ left: 12 })
.fontColor(item.completed ? '#AAAAAA' : '#333333')
.decoration({ type: item.completed ? TextDecorationType.LineThrough : TextDecorationType.None })
// 删除按钮
Text('✕')
.fontSize(18)
.fontColor('#FF5252')
.width(30)
.onClick(() => {
this.deleteTask(item.id)
})
}
.width('100%')
.padding(12)
.backgroundColor(Color.White)
.borderRadius(8)
}
}, (item: Todo) => `${item.id}-${item.completed}`)
}
.width('90%')
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
}
案例知识点回顾
| 知识点 | 在案例中的体现 |
|---|---|
interface |
定义 Todo 数据结构 |
@State |
管理 newTask、todoList 状态 |
@Entry / @Component |
页面入口组件 |
Column / Row |
整体布局 |
TextInput / Button / Text |
基础组件 |
List + ForEach |
渲染任务列表 |
| 箭头函数 | 事件处理回调 |
数组 map / filter |
修改和删除任务 |
| 模板字符串 | 统计文本拼接 |
| 三元运算符 | 条件样式判断 |
| getter | completedCount 计算属性 |
附录:学习路线建议
基础语法(变量/类型/函数)
↓
面向对象(类/接口/泛型)
↓
ArkUI 声明式布局(Column/Row/List)
↓
状态管理(@State/@Prop/@Link)
↓
实战项目(TodoList → 天气App → 网络请求)
↓
进阶(路由导航、网络请求、持久化存储、自定义组件)
练习建议 :把上面的 TodoList 案例亲手敲一遍,然后尝试扩展------加个"全部/未完成/已完成"筛选标签、加数据持久化(
@StorageProp或首选项),就是一个完整的上线级小应用了。