ArkTS 语言速查手册 — HarmonyOS 应用开发语言
# 📝 ArkTS 语言速查手册
ArkTS 是 HarmonyOS 应用开发的主语言。本文从 harmony 拆出并校订:原稿多处示例是不严谨的 TypeScript 写法(匿名对象类型、struct 访问器、生命周期归属、事件重复注册等),本文均已按官方规范修正,并在各节标注 ⚠️ 说明原写法问题。 装饰器清单已对照本机 DevEco SDK 声明文件(
ets-loader/declarations/common.d.ts)逐一核实。
# ArkTS 与 TypeScript 的关系
- 基于 TS 扩展:ArkTS 在 TypeScript 基础上扩展了声明式 UI(
struct/ 装饰器 /build())与并发能力(TaskPool/Worker 增强) - 比 TS 更严格:禁用
any/unknown;对象字面量必须有明确的类/接口类型;struct不支持普通 get/set 访问器 - 源文件后缀为
.ets;TS 是 ArkTS 的子集,但反过来不成立——TS 代码迁入.ets需按规范改写
# 1. 基础语法
# 变量声明
// 基本类型
let name: string = "HarmonyOS"
let version: number = 4.0
let isActive: boolean = true
// 数组
let devices: string[] = ["phone", "tablet", "tv"]
// 对象:ArkTS 要求对象字面量必须有明确的类/接口类型
// ⚠️ 原稿写法 let config: { name: string, version: number } = {...} 不合法:
// 匿名对象类型不属于 ArkTS 规范(arkts-no-untyped-obj-literals)
interface AppConfig {
name: string
version: number
}
let config: AppConfig = {
name: "MyApp",
version: 1.0
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 函数定义
// 普通函数
function greet(name: string): string {
return `Hello, ${name}!`
}
// 箭头函数
const calculate = (a: number, b: number): number => a + b
// 异步函数
async function fetchData(): Promise<string> {
return "data"
}
2
3
4
5
6
7
8
9
10
11
12
# 2. 状态装饰器(V1)
| 装饰器 | 严谨描述 |
|---|---|
@State | 组件内部状态;变量本身及其第一层属性变化触发当前组件 UI 刷新 |
@Prop | 父到子单向同步;子组件本地修改不会回传父组件(下次父组件同步时被覆盖)。早期仅支持基本类型/enum,API 11 起扩展支持对象、数组等复杂类型(子组件持有深拷贝副本) |
@Link | 父子双向同步;禁止本地初始化,父组件必须以 $变量 形式传入 |
@Observed | 装饰 class(不能装饰变量);单独使用无效果,需配合 @ObjectLink 才能观测嵌套类对象的一级属性变化 |
@ObjectLink | 子组件中接收 @Observed 类实例(禁止本地初始化),观测其一级属性变化 |
@Provide / @Consume | 祖先与后代双向同步,无需逐层传递 |
@Watch | 状态变量变化时的回调(仅监听,不改变数据流方向) |
@Component
struct TitleBar {
// @Prop:父到子单向同步,允许本地默认值
@Prop title: string = "Default Title"
// @Link:双向同步,禁止本地初始化,父组件须用 $变量 传入
@Link isVisible: boolean
build() {
Column() {
Text(this.title)
.fontSize(20)
Toggle({ type: ToggleType.Switch, isOn: this.isVisible })
.onChange((isOn: boolean) => {
this.isVisible = isOn
})
}
}
}
@Entry
@Component
struct MyComponent {
@State count: number = 0
@State visible: boolean = true
build() {
Column() {
// $visible 建立 @Link 双向链接
TitleBar({ title: "Counter", isVisible: $visible })
Button(`Count: ${this.count}`)
.onClick(() => {
this.count++
})
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
⚠️ 原稿把
@Link isVisible写在@Entry组件里——@Entry页面没有父组件,@Link无法初始化,运行时报错。@Link只能用于有父组件的子组件。
# 3. V2 状态管理(API 11+)
V1 与 V2 不能混用(同一组件/类只能选一套)。新项目建议 V2:
| V2 装饰器 | 说明 |
|---|---|
@ObservedV2 / @Trace | 类级/属性级精细观测,支持嵌套对象与数组元素变化(V1 只能观测第一层) |
@Local | 替代 V1 @State(仅组件内部状态,不与父组件同步) |
@Param / @Once / @Event | 替代 V1 @Prop/@Link:@Param 父到子单向、@Once 仅首次同步、@Event 子到父回调 |
@Computed | 计算属性,依赖变化自动重算 |
@Monitor | 替代 @Watch 的监听回调,可获取变化前后值 |
@ObservedV2
class NameModel {
@Trace firstName: string = "John"
@Trace lastName: string = "Doe"
// @Computed:依赖的 @Trace 属性变化时自动重算
@Computed
get fullName(): string {
return `${this.firstName} ${this.lastName}`
}
}
2
3
4
5
6
7
8
9
10
11
# 4. 组件开发
# 自定义组件
@Component
export struct CustomButton {
@Prop text: string = "Button"
onClick?: () => void
build() {
Button(this.text)
.onClick(() => {
this.onClick?.()
})
.backgroundColor(Color.Blue)
.borderRadius(8)
}
}
// 使用自定义组件
@Entry
@Component
struct MainPage {
build() {
Column() {
CustomButton({
text: "Click Me",
onClick: () => {
console.log("Button clicked!")
}
})
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 组件与页面生命周期
@Entry
@Component
struct LifecycleDemo {
// 组件生命周期:所有 @Component 均有
aboutToAppear() {
console.log("组件即将创建:build() 之前调用")
}
aboutToDisappear() {
console.log("组件即将销毁")
}
// 页面生命周期:仅 @Entry 页面组件拥有
onPageShow() {
console.log("页面显示(路由进入/应用切前台)")
}
onPageHide() {
console.log("页面隐藏(路由离开/应用切后台)")
}
onBackPress() {
console.log("用户按返回键")
return false
}
build() {
Text("Lifecycle Demo")
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
⚠️ 原稿把
onPageShow/onPageHide写在普通@Component里——它们是@Entry页面级生命周期,在普通自定义组件中定义永远不会被调用。执行顺序:aboutToAppear→build()→ 页面显示后onPageShow。
# 5. 数据绑定
# 单向绑定(状态驱动 UI)
@Entry
@Component
struct DataBindingDemo {
@State message: string = "Hello HarmonyOS"
build() {
Column() {
// 状态变化自动触发 build 刷新
Text(this.message)
.fontSize(20)
Button("Update Message")
.onClick(() => {
this.message = "Updated Message"
})
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 双向绑定($$ 语法)
@Entry
@Component
struct TwoWayBinding {
@State inputText: string = ""
build() {
Column() {
// $$:内置组件参数与状态变量的双向同步
// 输入框内容变化自动写回 inputText,无需 onChange 手动赋值
TextInput({ text: $$this.inputText, placeholder: "Enter text" })
Text(`You typed: ${this.inputText}`)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
⚠️ 原稿"双向绑定"示例实为
onChange手动赋值——那是"单向 + 手动回写",不是声明式双向绑定。$$仅用于特定内置组件参数(TextInput.text、Slider.value等);不在支持列表内的组件仍需onChange手动同步。
# 计算属性
// 见 §3 的 @Computed 示例
⚠️ 原稿在
struct里直接写get fullName(): string——struct 不支持普通 get/set 访问器(ArkTS 规范外用法,Code Linter 报错)。派生值应使用方法,或 V2 的@Computed(配合@ObservedV2类)。
# 6. 事件处理
# 点击事件
@Component
struct EventHandling {
@State count: number = 0
private handleClick(): void {
this.count++
console.log(`Button clicked ${this.count} times`)
}
build() {
Column() {
Button(`Click Count: ${this.count}`)
// 推荐箭头函数包裹,this 语义明确
.onClick(() => {
this.handleClick()
console.log("Inline click handler")
})
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
⚠️ 两个原稿问题:
- 同一组件链式调用两次
.onClick(),后者覆盖前者(事件是覆盖式注册,不是追加)。需要多个动作请在同一个回调内完成.onClick(this.handleClick)直接传方法引用,建议改为() => this.handleClick(),避免 this 绑定歧义
# 手势事件
// ArkTS 不允许匿名对象类型,先定义 class
class Position {
x: number = 0
y: number = 0
}
@Component
struct GestureDemo {
@State position: Position = new Position()
build() {
Column() {
Text(`x: ${this.position.x}, y: ${this.position.y}`)
.gesture(
PanGesture({ fingers: 1, direction: PanDirection.All })
.onActionStart(() => {
console.log("Pan started")
})
.onActionUpdate((event: GestureEvent) => {
// @State 可观测 class 实例一级属性赋值
this.position.x = event.offsetX
this.position.y = event.offsetY
})
.onActionEnd(() => {
console.log("Pan ended")
})
)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
⚠️ 原稿
@State position: { x: number, y: number } = { x: 0, y: 0 }使用匿名对象类型,不合法,须改为 class。
# 7. 状态管理分层
| 层级 | 机制 | 说明 |
|---|---|---|
| 应用级 | AppStorage | 应用全局状态,配合 @StorageLink/@StorageProp 或 API 读写 |
| 应用级(持久化) | PersistentStorage | 将 AppStorage 中的状态持久化到磁盘 |
| 环境 | Environment | 设备环境变量(只读),如屏幕宽度 |
| 页面级 | LocalStorage | UIAbility 内页面间共享,配合 @LocalStorageLink/@LocalStorageProp |
| 组件级 | @State/@Prop/@Link 等 | 见 §2/§3 |
⚠️ 原稿列出过
SessionStorage——ArkUI 不存在此 API(那是浏览器的概念),页面级共享用LocalStorage。
# 8. 常见坑速查(从本稿校订沉淀)
| 坑 | 说明 |
|---|---|
any / unknown | ArkTS 禁用(arkts-no-any);JSON.parse 需定义接口/类后类型断言 |
| 匿名对象类型 | let x: { a: string } 不合法,须 interface/class |
| struct 访问器 | struct 不支持普通 get/set;计算属性用 V2 @Computed 或方法 |
@Entry 中 @Link | @Entry 无父组件,@Link 无法初始化,运行时报错 |
| 事件重复注册 | .onClick() 链式多次调用是覆盖不是追加 |
onPageShow 位置 | 仅 @Entry 页面生效,普通 @Component 中无效 |
| V1/V2 混用 | 同一组件/类只能选一套状态管理装饰器 |
@Prop 复杂类型 | class/数组需 API 11+;且子组件持有深拷贝,修改不回传父组件 |