文章

ArkTS基础语法深度解析

ArkTS基础语法深度解析

一句话概括: ArkTS 是鸿蒙(HarmonyOS)原生应用开发的官方语言,基于 TypeScript 扩展了声明式 UI、装饰器和状态管理语法,是连接 Web 开发习惯与原生性能的关键桥梁。

1. 背景与意义

2024 年,华为正式发布了 HarmoyOS NEXT(鸿蒙星河版),实现了完全去安卓化的独立操作系统。在这一系统中,传统的 Java/Kotlin 开发方式被一种全新的语言替代——ArkTS

ArkTS 不是凭空创造的语言。它基于 TypeScript——TypeScript 又是 JavaScript 的超集。这意味着如果你有 Web 前端(尤其是 Angular/React)的开发经验,ArkTS 对你来说不会有太大的违和感。

但 ArkTS 不是简单的”TypeScript for mobile”。它做了三件关键的事情:

  1. 静态类型增强:在 TypeScript 的基础上进一步强化了类型系统,引入了编译时类型检查
  2. 声明式 UI 语法:借鉴了 Flutter 和 SwiftUI 的声明式思想,通过 @Component 装饰器定义 UI
  3. 状态管理原语:通过 @State@Prop@Link 等装饰器实现组件间状态同步

ArkTS 的设计哲学可以概括为:保留 TypeScript 的开发体验,赋予原生级别的性能

对于 Flutter 开发者来说,ArkTS 的声明式 UI 和状态管理概念应该很熟悉——只是语法从 Dart 换成了 TypeScript。对于前端开发者来说,它的 Decorator 语法和组件化思想与 Angular 非常接近。这正是鸿蒙生态希望吸引的那群开发者——用他们熟悉的工具链来构建鸿蒙应用。

2. 概念与定义

2.1 ArkTS 语法层级

ArkTS 的语言体系可以划分为三个层级:

flowchart TD
    A[ArkTS 语言层级] --> B[基础层<br/>TypeScript 语法]
    A --> C[扩展层<br/>ArkTS 特有语法]
    A --> D[框架层<br/>声明式 UI & 装饰器]
    
    subgraph Base[TypeScript 基础]
        B1[变量声明<br/>let / const]
        B2[基本类型<br/>string, number, boolean]
        B3[接口 Interface]
        B4[类 Class]
        B5[异步 async/await]
        B6[泛型 Generics]
    end
    
    subgraph Ext[ArkTS 扩展]
        C1[禁止 any/unknown]
        C2[禁止 JS 动态特性]
        C3[增强类型推导]
        C4[编译时检查]
    end
    
    subgraph Framework[声明式 UI]
        D1[@Component<br/>组件装饰器]
        D2[@State<br/>内部状态]
        D3[@Prop<br/>父传子]
        D4[@Link<br/>双向绑定]
        D5[@Watch<br/>状态监听]
        D6[build() 方法<br/>UI 构建]
    end
    
    B --- B1
    B --- B2
    C --- C1
    D --- D1

2.2 核心概念与装饰器

ArkTS 中的装饰器(Decorator)是其声明式 UI 的基石:

装饰器作用类似概念
@Component标记一个类为 UI 组件Flutter 的 StatelessWidget
@State声明可变状态,变化时自动触发 UI 更新Flutter 的 ChangeNotifier
@Prop接收父组件的单向传入值React 的 props
@Link接收父组件传入的引用,支持双向绑定Vue 的 v-model
@Watch监听某个 State 变量的变化Vue 的 watch
@StorageProp持久化存储属性SharedPreferences
@Consume从祖先组件获取状态React Context
@Builder构建函数,用于嵌入 UI 逻辑Flutter 的 method

3. 最小示例:计数器

1
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
38
39
40
41
42
43
44
45
46
// === 最简 ArkTS 计数器 ===

// 导入 ArkUI 基础库
import { Component, State, Build, Content } from '@ohos/arkui';

// @Entry 标记该组件为应用的入口
@Entry
// @Component 标记该类为 UI 组件
@Component
struct CounterApp {
  // @State 标记该变量为状态变量
  // 当 count 变化时,所有依赖它的 UI 会自动更新
  @State count: number = 0;

  // build 方法定义 UI 结构
  build() {
    // Column 是纵向布局容器,类似 Flutter 的 Column
    Column() {
      // Text 组件显示文本
      Text('计数: ' + this.count)
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 20 })

      Row() {
        Button('增加')
          .onClick(() => {
            // 直接修改 State 变量,UI 自动更新
            this.count++;
          })
          .margin({ right: 10 })
          .backgroundColor(Color.Blue)

        Button('减少')
          .onClick(() => {
            this.count--;
          })
          .backgroundColor(Color.Red)
      }
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
  }
}

这个计数器示例展示了 ArkTS 的几个核心特性:

  1. struct 定义组件:ArkTS 使用 struct(而非 class)来定义组件,这是一种值类型的组件定义方式
  2. @State 装饰器:被 @State 修饰的变量是响应式的,修改时自动触发 UI 重建
  3. 链式属性设置:类似 Flutter 的级联写法,通过 .fontSize(30).width('100%') 设置属性
  4. Lambda 事件:通过 .onClick(() => { this.count++ }) 绑定事件
  5. Flex 布局:Column 和 Row 控制布局方向,justifyContentalignItems 控制对齐

3.1 与 TypeScript 的对比

如果你从 TypeScript 迁移到 ArkTS,需要注意以下差异:

1
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
// TypeScript 中允许的写法:
let x: any = 'hello';  // ❌ ArkTS 中不允许 any
let y: unknown = 42;   // ❌ ArkTS 中不允许 unknown

// ArkTS 中必须明确类型:
let x: string = 'hello';
let y: number = 42;

// TypeScript 中允许动态属性:
const obj: any = {};
obj.someNewProp = 42;  // ❌ ArkTS 中不允许

// ArkTS 中必须在接口中声明:
interface MyObj {
  someNewProp: number;
}
const obj: MyObj = { someNewProp: 42 };

// TypeScript 中允许函数重载:
function greet(name: string): string;
function greet(age: number): string;
function greet(param: string | number): string {
  return `Hello, ${param}`;
}
// ✅ ArkTS 中支持(需使用相同返回类型)

// TypeScript 中允许 prototype 操作:
String.prototype.capitalize = function() { // ❌ ArkTS 不允许
  return this.charAt(0).toUpperCase();
};

ArkTS 的类型系统比 TypeScript 更严格——它禁止 any、禁止 prototype 操作、禁止运行时类型添加、禁止 with 语句。这些限制的目的是让编译器能够进行更激进的优化,实现原生级别的性能。

4. 核心知识点拆解

4.1 声明式 UI 构建

ArkTS 的 UI 构建通过 build() 方法实现,语法类似组合函数调用:

1
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
38
39
40
41
42
43
44
@Component
struct UserCard {
  @Prop name: string;
  @Prop avatar: string;
  @Prop isOnline: boolean;

  build() {
    // Row 作为根容器
    Row() {
      // 头像区域
      Stack() {
        Image(this.avatar)
          .width(48)
          .height(48)
          .borderRadius(24)

        // 在线状态指示器
        if (this.isOnline) {
          Circle()
            .width(12)
            .height(12)
            .fill(Color.Green)
            .position({ x: 36, y: 36 })
        }
      }

      // 文字信息
      Column() {
        Text(this.name)
          .fontSize(16)
          .fontWeight(FontWeight.Bold)

        Text(this.isOnline ? '在线' : '离线')
          .fontSize(12)
          .fontColor(Color.Gray)
      }
      .margin({ left: 12 })
    }
    .padding(12)
    .borderRadius(8)
    .backgroundColor(Color.White)
    .shadow({ radius: 4, color: '#20000000' })
  }
}

ArkTS 的声明式 UI 语法有几个特点:

条件渲染:直接在 build() 中使用 if 语句

1
2
3
4
if (this.isOnline) {
  Circle() // 仅在在线时显示
    .width(12).height(12).fill(Color.Green)
}

循环渲染:使用 ForEach 组件

1
2
3
ForEach(this.items, (item: string, index: number) => {
  Text(item).fontSize(16)
}, (item: string) => item) // key 生成器

链式 API:通过 . 链式调用设置属性

1
2
3
4
5
Text('Hello')
  .fontSize(20)
  .fontColor(Color.Blue)
  .fontWeight(FontWeight.Bold)
  .textAlign(TextAlign.Center)

4.2 状态管理的装饰器体系

1
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
@Component
struct TodoItem {
  // @Prop:从父组件传入,只读(单向)
  @Prop id: string;
  @Prop title: string;

  // @State:组件内部状态,私有
  @State isCompleted: boolean = false;

  // @Link:与父组件双向绑定
  @Link totalCount: number;

  // @Watch:监听状态变化
  @Watch('onCompletedChange')
  @State isFavorite: boolean = false;

  onCompletedChange() {
    // 当 isFavorite 或 isCompleted 变化时触发
    console.log('状态变化:', this.isFavorite);
  }

  build() {
    Row() {
      Checkbox()
        .select(this.isCompleted)
        .onChange((value: boolean) => {
          this.isCompleted = value;
          if (value) {
            this.totalCount--; // 修改 @Link 变量
          }
        })

      Text(this.title)
        .decoration({
          type: this.isCompleted
            ? TextDecorationType.LineThrough
            : TextDecorationType.None
        })

      Image(this.isFavorite ? '/icons/heart_filled.png' : '/icons/heart_empty.png')
        .width(24)
        .height(24)
        .onClick(() => {
          this.isFavorite = !this.isFavorite;
        })
    }
  }
}

// 父组件
@Entry
@Component
struct TodoList {
  @State items: TodoData[] = [
    { id: '1', title: '学习 ArkTS 语法' },
    { id: '2', title: '完成 UI 布局' },
  ];
  @State remainingCount: number = 2;

  build() {
    Column() {
      Text('待办事项 (剩余: ' + this.remainingCount + ')')
        .fontSize(20)
        .margin({ bottom: 16 })

      ForEach(this.items, (item: TodoData, index: number) => {
        // 使用 @Link 实现双向绑定
        TodoItem({
          id: item.id,
          title: item.title,
          totalCount: $remainingCount // $ 前缀获取 @Link 引用
        })
      }, (item: TodoData) => item.id)
    }
    .padding(16)
    .width('100%')
  }
}

interface TodoData {
  id: string;
  title: string;
}

@State、@Prop、@Link 三个装饰器构成了 ArkTS 状态管理的基本框架:

  • @State:组件内部的响应式状态,修改后自动更新 UI
  • @Prop:父组件单向传入的静态数据,子组件不能修改
  • @Link:父组件通过 $变量名 传入的引用,父子双向同步

4.3 自定义构建函数 (@Builder)

@Builder 装饰器允许你定义可复用的 UI 构建逻辑:

1
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
38
39
40
41
42
43
44
45
46
@Component
struct ProductList {
  @State products: Product[] = [];

  // 自定义构建函数——复用卡片样式
  @Builder
  ProductCard(product: Product) {
    Row() {
      Image(product.thumbnail)
        .width(80)
        .height(80)
        .borderRadius(8)

      Column() {
        Text(product.name)
          .fontSize(16)
          .fontWeight(FontWeight.Bold)

        Text('¥' + product.price.toFixed(2))
          .fontSize(14)
          .fontColor(Color.Red)

        Rating({ rating: product.rating, stars: 5 })
          .starSize(14)
      }
      .margin({ left: 12 })
      .alignItems(HorizontalAlign.Start)
    }
    .padding(12)
    .borderRadius(12)
    .backgroundColor(Color.White)
    .shadow({ radius: 4, color: '#15000000' })
    .margin({ bottom: 8 })
  }

  build() {
    List() {
      ForEach(this.products, (product: Product) => {
        ListItem() {
          // 调用 @Builder 构建函数
          this.ProductCard(product)
        }
      }, (product: Product) => product.id)
    }
  }
}

@Builder 与普通函数的区别:@Builder 可以使用状态变量,并且在状态变化时会自动更新。它不能在 struct 外部定义或者作为独立函数导出。

4.4 生命周期

ArkTS 组件提供了完整的生命周期钩子:

1
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
38
39
40
41
42
43
44
45
46
@Entry
@Component
struct LifecycleDemo {
  @State data: string = '';

  aboutToAppear() {
    // 组件即将显示——执行初始化
    // 类似于 Flutter 的 initState
    console.log('aboutToAppear');
    this.loadData();
  }

  onPageShow() {
    // 页面显示时触发(包括从后台返回)
    console.log('onPageShow');
  }

  onPageHide() {
    // 页面隐藏时触发(切到后台或导航至其他页面)
    console.log('onPageHide');
  }

  aboutToDisappear() {
    // 组件即将销毁——清理资源
    // 类似于 Flutter 的 dispose
    console.log('aboutToDisappear');
  }

  loadData() {
    // 模拟数据加载
    setTimeout(() => {
      this.data = '加载完成';
    }, 1000);
  }

  build() {
    Column() {
      if (this.data) {
        Text(this.data)
          .fontSize(20)
      } else {
        LoadingProgress()
      }
    }
  }
}

生命周期方法在 ArkTS 中作为 struct 的方法定义,不需要 override 关键字。框架会自动识别并调用它们。

5. 实战案例:待办事项管理器

构建一个完整的待办事项管理器,展示 ArkTS 的综合能力:

1
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
// === 1. 数据模型 ===
interface Task {
  id: number;
  title: string;
  completed: boolean;
  priority: 'high' | 'medium' | 'low';
  createdAt: number;
}

// === 2. 自定义组件:任务列表项 ===
@Component
struct TaskItem {
  @Link task: Task;
  @Link onDelete: (id: number) => void;

  build() {
    SwipeAction({
      end: {
        builder: () => {
          Button('删除')
            .backgroundColor(Color.Red)
            .fontColor(Color.White)
            .onClick(() => {
              this.onDelete(this.task.id);
            })
        }
      }
    }) {
      Row() {
        // 复选框
        Checkbox()
          .select(this.task.completed)
          .onChange((value: boolean) => {
            this.task.completed = value;
          })

        Column() {
          Text(this.task.title)
            .fontSize(16)
            .decoration({
              type: this.task.completed
                ? TextDecorationType.LineThrough
                : TextDecorationType.None
            })
            .fontColor(this.task.completed ? Color.Gray : Color.Black)

          // 优先级标签
          Text(this.task.priority === 'high' ? '高优先级' :
               this.task.priority === 'medium' ? '中优先级' : '低优先级')
            .fontSize(12)
            .fontColor(
              this.task.priority === 'high' ? Color.Red :
              this.task.priority === 'medium' ? Color.Orange : Color.Gray
            )
        }
        .margin({ left: 8 })
      }
      .padding(12)
      .width('100%')
    }
  }
}

// === 3. 新增任务弹窗 ===
@Component
struct AddTaskDialog {
  private onAdd: (title: string, priority: Task['priority']) => void;
  @State title: string = '';
  @State selectedPriority: Task['priority'] = 'medium';

  build() {
    Column() {
      Text('新增任务')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 16 })

      TextInput({ placeholder: '输入任务名称' })
        .onChange((value: string) => {
          this.title = value;
        })
        .height(44)
        .borderRadius(8)
        .backgroundColor('#F5F5F5')
        .padding({ left: 12, right: 12 })

      Row() {
        Text('优先级: ').fontSize(14)
        RadioGroup({
          group: 'priority',
          selected: this.selectedPriority
        }) {
          Radio({ value: 'low' })
          Text('')

          Radio({ value: 'medium' })
          Text('')

          Radio({ value: 'high' })
          Text('')
        }
        .onChange((value: string) => {
          this.selectedPriority = value as Task['priority'];
        })
      }
      .margin({ top: 16, bottom: 24 })

      Row() {
        Button('取消')
          .backgroundColor(Color.Gray)
          .fontColor(Color.White)
          .onClick(() => {
            // 关闭弹窗
          })

        Button('添加')
          .backgroundColor(Color.Blue)
          .fontColor(Color.White)
          .enabled(this.title.length > 0)
          .onClick(() => {
            if (this.title.length > 0) {
              this.onAdd(this.title, this.selectedPriority);
              this.title = '';
            }
          })
      }
      .justifyContent(FlexAlign.SpaceAround)
      .width('100%')
    }
    .padding(24)
    .borderRadius(16)
    .backgroundColor(Color.White)
  }
}

// === 4. 主页面 ===
@Entry
@Component
struct TaskManager {
  @State tasks: Task[] = [
    {
      id: 1,
      title: '学习 ArkTS 基础语法',
      completed: true,
      priority: 'high',
      createdAt: Date.now()
    },
    {
      id: 2,
      title: '完成鸿蒙 UI 布局练习',
      completed: false,
      priority: 'medium',
      createdAt: Date.now()
    }
  ];

  @State filter: 'all' | 'active' | 'completed' = 'all';
  @State showAddDialog: boolean = false;

  // 计算属性
  get filteredTasks(): Task[] {
    if (this.filter === 'active') {
      return this.tasks.filter(t => !t.completed);
    } else if (this.filter === 'completed') {
      return this.tasks.filter(t => t.completed);
    }
    return this.tasks;
  }

  get activeCount(): number {
    return this.tasks.filter(t => !t.completed).length;
  }

  addTask(title: string, priority: Task['priority']) {
    const newTask: Task = {
      id: Date.now(),
      title: title,
      completed: false,
      priority: priority,
      createdAt: Date.now()
    };
    this.tasks = [...this.tasks, newTask];
    this.showAddDialog = false;
  }

  deleteTask(id: number) {
    this.tasks = this.tasks.filter(t => t.id !== id);
  }

  build() {
    Column() {
      // 头部统计
      Row() {
        Text('待办事项')
          .fontSize(24)
          .fontWeight(FontWeight.Bold)

        Text('剩余 ' + this.activeCount + '')
          .fontSize(14)
          .fontColor(Color.Gray)
      }
      .width('100%')
      .justifyContent(FlexAlign.SpaceBetween)
      .padding({ top: 24, bottom: 8, left: 16, right: 16 })

      // 过滤标签
      Row() {
        this.FilterChip('全部', 'all')
        this.FilterChip('待完成', 'active')
        this.FilterChip('已完成', 'completed')
      }
      .padding({ left: 12, right: 12 })
      .margin({ bottom: 8 })

      // 任务列表
      List() {
        ForEach(this.filteredTasks, (task: Task) => {
          ListItem() {
            TaskItem({
              task: $task,
              onDelete: (id: number) => this.deleteTask(id)
            })
          }
        }, (task: Task) => task.id.toString())
      }
      .layoutWeight(1) // 填充剩余空间

      // 添加按钮
      Button() {
        Row() {
          SymbolGlyph({ name: 'plus' }).fontSize(20)
          Text('新增任务').fontSize(16)
        }
      }
      .width('90%')
      .backgroundColor(Color.Blue)
      .fontColor(Color.White)
      .borderRadius(25)
      .height(48)
      .margin({ bottom: 24 })
      .onClick(() => {
        this.showAddDialog = true;
      })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F0F0F0')
  }

  // 过滤器 Chip 组件
  @Builder
  FilterChip(label: string, value: 'all' | 'active' | 'completed') {
    Text(label)
      .fontSize(14)
      .fontColor(this.filter === value ? Color.White : Color.Black)
      .backgroundColor(this.filter === value ? Color.Blue : '#E0E0E0')
      .borderRadius(16)
      .padding({ left: 16, right: 16, top: 6, bottom: 6 })
      .margin({ right: 8 })
      .onClick(() => {
        this.filter = value;
      })
  }
}

这个完整的待办事项管理器展示了 ArkTS 的核心能力:

  1. @State 和数组状态管理:通过 this.tasks = [...this.tasks, newTask] 更新数组触发 UI 重建
  2. @Link 父子组件双向绑定:使 TaskItem 能直接修改父组件的 task 数据
  3. @Builder 复用构建函数:FilterChip 作为 @Builder 在同一个 struct 中复用
  4. 条件渲染:通过 if 语句控制 UI 分支
  5. 事件处理:onClick、onChange、onSwipe 等事件绑定
  6. List + ForEach 列表渲染:列表项按需构建和回收

6. 底层原理

6.1 装饰器与编译器

ArkTS 的装饰器(如 @Component@State)并不是 JavaScript 的装饰器提案(stage 3)的实现。它们是编译器级别的语法糖,在编译阶段被转换为框架的元数据:

1
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
// 开发者写的 ArkTS 代码(编译前)
@Component
struct MyButton {
  @State count: number = 0;

  build() {
    Button('点击: ' + this.count)
      .onClick(() => {
        this.count++;
      })
  }
}

// 编译器处理后(伪代码)
const MyButton = {
  metadata: {
    state: ['count'],
    template: (ctx) => {
      return {
        type: 'Button',
        props: {
          text: '点击: ' + ctx.count,
          onClick: () => { ctx.count++; }
        }
      };
    }
  }
};

编译器会将 @Component struct 转化为一个配置对象,将 @State count 注册到响应式追踪系统中。当 count 的值变化时,追踪系统标记该组件为”需要更新”。

6.2 响应式更新机制

ArkTS 的响应式系统核心是一个依赖追踪(dependency tracking)引擎:

1
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
// 伪代码:ArkTS 响应式系统的核心
class ReactiveSystem {
  private static dirtyComponents: Set<Component> = new Set();
  private static currentComponent: Component | null = null;

  // 在 build() 执行时注册当前组件的依赖
  static beginComponentBuild(component: Component) {
    this.currentComponent = component;
    component.dependencies.clear();
  }

  // 当 State 变量被读取时,记录依赖关系
  static onStateRead(owner: Component, key: string) {
    if (this.currentComponent) {
      this.currentComponent.dependencies.add({ owner, key });
    }
  }

  // 当 State 变量被修改时,标记相关的组件为 dirty
  static onStateWrite(owner: Component, key: string) {
    for (const dep of allDependencies) {
      if (dep.owner === owner && dep.key === key) {
        this.dirtyComponents.add(dep.consumer);
      }
    }
    // 在下一帧(vsync)触发 UI 更新
    requestAnimationFrame(this.flushUpdates);
  }
}

这就是为什么你只需要修改 @State 变量的值,UI 就会自动更新——编译器在 build 方法执行时记录所有读取了哪些 State,当 State 变化时找到所有依赖它的组件并触发更新。

6.3 ArkTS 与 Flutter 在底层上的异同

虽然 ArkTS 和 Flutter 都采用了声明式 UI,但它们的底层实现有显著差异:

维度ArkTSFlutter
UI 描述语言ArkTS (TypeScript 方言)Dart
渲染引擎鸿蒙自研渲染引擎Skia / Impeller
Widget 模型轻量 struct (值类型)Widget (不可变对象)
状态更新自动追踪依赖手动 notifyListeners
跨平台仅鸿蒙Android/iOS/Web/Desktop
编译方式AOT + JIT 混合AOT (release)

ArkTS 通过编译阶段的代码变换(transform)来注入响应式逻辑,这也是为什么它需要禁用 any 等特性——编译器需要确切的类型信息才能在编译时生成高效的更新代码。

7. 高频面试题解析

Q1: ArkTS 和 TypeScript 的主要区别是什么?

答: ArkTS 是 TypeScript 的子集,同时做了扩展。区别包括:ArkTS 禁止使用 any 和 unknown 类型,禁止动态添加属性,禁止 prototype 操作,禁止 with 语句。这些限制是为了支持编译时的充分优化。扩展方面,ArkTS 加入了 @Component、@State、@Prop、@Link 等装饰器用于声明式 UI。另外,ArkTS 使用 struct 而非 class 来定义组件,struct 是值类型,有更好的内存局域性和性能表现。

Q2: @State 和 @Prop 有什么区别?

答: @State 用于声明组件内部的私有状态,该状态只能被当前组件修改。@Prop 用于接收父组件的单向传入值,子组件不能修改 @Prop 修饰的变量。如果需要在子组件中修改并同步到父组件,使用 @Link。简单理解:@State = 自己的数据,@Prop = 别人的只读数据,@Link = 别人的可写数据。

Q3: ArkTS 中如何实现组件间的状态共享?

答: ArkTS 提供了多种跨组件状态共享机制。对于父子组件:使用 @Prop(单向)或 @Link(双向)。对于兄弟组件:将状态提升到共同的父组件中管理。对于深层嵌套组件:使用 @Consume(类似 React 的 Context)。此外还有 @StorageProp 实现跨页面的持久化存储。这些机制一起构成了 ArkTS 的完整状态管理方案。

Q4: ArkTS 中的 build 方法可以包含哪些类型的语句?

答: build 方法遵循严格的声明式语法规则,允许的语句包括:条件语句(if/else)、循环渲染(ForEach)、链式调用设置属性、调用 @Builder 构建函数、嵌套其他容器组件。但禁止在 build 中执行副作用操作(如网络请求、文件读写),这些应在生命周期方法中处理。另外,build 方法返回的必须是 @Component 修饰的组件树的根节点。

Q5: 如何在 ArkTS 中处理异步操作?

答: ArkTS 支持 TypeScript 的 async/await。异步操作通常在 aboutToAppear 生命周期中发起,或在 onClick 等事件处理中触发。由于 ArkTS 的 UI 更新是自动的,你只需要在异步操作完成后更新 @State 变量即可。例如:

1
2
3
4
5
6
7
@State userData: UserData | null = null;

async aboutToAppear() {
  const response = await fetch('https://api.example.com/user');
  this.userData = await response.json();
  // 赋值后自动触发 UI 重建
}

注意:在 ArkTS 中,所有的异步操作都应该使用 async/await,避免使用 Promise 的 .then() 链式调用。

8. 总结与扩展

ArkTS 是鸿蒙生态的核心编程语言,它用 TypeScript 开发者熟悉的语法,实现了原生级别的性能和声明式 UI。如果你有前端背景,学习 ArkTS 的学习曲线会比学习 Kotlin 或 Java 平缓得多。

ArkTS 的核心要点:

  • Struct 组件:值类型的组件定义,更好的性能和内存布局
  • 装饰器驱动:@Component、@State、@Prop、@Link 构成完整的组件和状态体系
  • 链式 API:通过 . 链式调用来设置 UI 属性
  • 自动响应式:修改 @State 变量自动触发 UI 更新
  • 编译时优化:严格的类型约束使编译器能够生成高效代码

对于 Flutter 开发者,ArkTS 的声明式 UI 和状态管理概念是相通的——区别主要在于语法和装饰器的使用方式。对于前端开发者,ArkTS 的 TypeScript 基础和装饰器语法应该驾轻就熟。

随着鸿蒙生态的持续发展和 HarmonyOS NEXT 的全面铺开,ArkTS 将成为跨端开发领域不可忽视的一环。掌握 ArkTS,意味着你拥有了进入鸿蒙生态的钥匙。


本系列文章已覆盖 Flutter 状态管理、渲染性能、列表优化、动画性能、调试工具、完整优化体系以及 ArkTS 基础语法,构成了完整的跨端开发知识框架。

本文由作者按照 CC BY 4.0 进行授权

© 独行的风. 保留部分权利。

本站采用 Jekyll 主题 Chirpy

本站总访问量 本站访客数 本文阅读量