4. ArkTS语言入门:从Java/Kotlin到ArkTS
说实话,第一次接触ArkTS的时候,我心里是有点抵触的。毕竟在安卓圈摸爬滚打了七八年,Java和Kotlin早就成了肌肉记忆。但当我真正上手写了几个页面之后,嗯,真香了。
这一章,我就带你快速过一遍ArkTS的核心。咱们不搞学院派那套,直接说人话。
4.1 从Java/Kotlin到TypeScript:你其实已经会了一半
先给你吃颗定心丸:如果你写过Kotlin,那ArkTS对你来说就是换个写法的事。ArkTS基于TypeScript,而TypeScript说白了就是带类型的JavaScript。
我见过很多安卓开发者看到TypeScript就发怵,觉得是前端的东西。其实不然。你想想看,Kotlin和TypeScript的很多设计理念是相通的:
- 类型系统:Kotlin有可空类型,TypeScript有联合类型和可选链
- Lambda表达式:Kotlin的
{ it -> doSomething() }对应TypeScript的=> doSomething() - 数据类:Kotlin的
data class对应TypeScript的interface或class
核心认知:ArkTS不是让你重新学一门语言,而是让你用熟悉的思维写新的语法。
4.2 TypeScript基础速通:够用就行
我不打算把TypeScript的所有特性都讲一遍,那得再开一门课。咱们只挑ArkTS开发中最常用的几个点。
4.2.1 类型声明
在Kotlin里你写 val name: String = "Hello",在TypeScript里你写:
let name: string = "Hello"
const age: number = 25
let isActive: boolean = true
注意,TypeScript用 let 和 const 代替了 var。我个人习惯能用 const 就用 const,减少变量被意外修改的风险。我在项目中遇到过因为用了 var 导致作用域污染的问题,排查了半天才发现是变量提升搞的鬼。
4.2.2 接口与类型别名
Kotlin的 data class 在TypeScript里可以用 interface 或 type 来替代:
// 接口方式(推荐)
interface User {
id: number
name: string
email?: string // 可选属性
}
// 类型别名方式
type User = {
id: number
name: string
email?: string
}
我个人更倾向于用 interface,因为它在扩展性上更好。但如果你需要联合类型,那就得用 type。
4.2.3 函数与箭头函数
Kotlin的函数定义和TypeScript的箭头函数,其实是一回事:
// Kotlin
fun greet(name: String): String {
return "Hello, $name"
}
// TypeScript
const greet = (name: string): string => {
return `Hello, ${name}`
}
这里有个小坑:TypeScript的模板字符串用的是反引号 `,不是单引号。我第一次写的时候习惯性地用了单引号,结果编译报错,愣是看了半天才反应过来。
小技巧:如果你觉得箭头函数不习惯,也可以用普通函数声明:function greet(name: string): string { ... }。ArkTS都支持。
4.3 ArkTS的声明式UI语法:这才是重头戏
好了,语言基础说完了。现在咱们聊聊ArkTS最核心的东西——声明式UI。
如果你用过Jetpack Compose,那你会觉得ArkTS的写法非常亲切。如果你没用过,也没关系,我带你从零开始。
4.3.1 组件结构
在ArkTS里,一个页面就是一个 @Component 装饰的类:
@Component
struct HelloPage {
build() {
Column() {
Text("Hello, ArkTS!")
.fontSize(24)
.fontWeight(FontWeight.Bold)
Button("点击我")
.onClick(() => {
console.info("按钮被点击了")
})
}
.padding(16)
}
}
你看,整个UI就是一层层嵌套的结构。 Column 相当于垂直布局, Text 是文本, Button 是按钮。每个组件后面可以链式调用一堆方法,比如 .fontSize()、.padding(),用来设置样式。
我曾经在项目里看到有人把样式写成了这样:
Text("Hello")
Text("World")
.fontSize(20)
结果第二个Text的样式没生效。为什么?因为ArkTS的链式调用只作用于前一个组件,不能跨组件。嗯,这里要注意,每个组件的样式要单独设置。
4.3.2 状态管理:@State 和 @Prop
声明式UI的核心是状态驱动。说白了,就是数据变了,UI自动跟着变。
在ArkTS里,用 @State 装饰的变量就是状态:
@Component
struct CounterPage {
@State count: number = 0
build() {
Column() {
Text(`计数: ${this.count}`)
.fontSize(28)
Button("加一")
.onClick(() => {
this.count++
})
}
}
}
每次点击按钮, count 加1, Text 自动更新。你不需要手动去调用 setText() 或者 notifyDataSetChanged(),框架帮你做了。
如果你想把数据传给子组件,就用 @Prop:
@Component
struct ChildComponent {
@Prop message: string
build() {
Text(this.message)
}
}
@Entry
@Component
struct ParentPage {
build() {
ChildComponent({ message: "来自父组件的数据" })
}
}
注意:@State 是组件内部的状态,@Prop 是从父组件传进来的数据。不要搞混了。我见过有人把 @Prop 当 @State 用,结果在子组件里修改了数据,父组件那边完全不知道,排查了半天。
4.3.3 列表渲染:ForEach
在安卓里你要写 RecyclerView + Adapter,在ArkTS里只需要一个 ForEach:
@Component
struct ListPage {
@State items: string[] = ["苹果", "香蕉", "橘子"]
build() {
Column() {
ForEach(this.items, (item: string, index: number) => {
Text(`${index + 1}. ${item}`)
.fontSize(18)
.padding(8)
})
}
}
}
你看,不需要 ViewHolder,不需要 onBindViewHolder,一个循环搞定。而且数据变了,列表自动刷新。
不过要注意, ForEach 的第二个参数是回调函数,里面返回的是UI组件。如果你需要复杂的列表项,可以单独抽成一个组件。
4.4 知识体系总览
为了让你对ArkTS的整体结构有个直观印象,我画了一张图:
4.5 避坑指南
最后,分享几个我踩过的坑,希望能帮你省点时间:
- 不要直接修改数组:在ArkTS里,如果你用
this.items[0] = "新值",UI不会刷新。必须用this.items.splice(0, 1, "新值")或者重新赋值整个数组。 - @State 只监听第一层:如果你的状态是一个对象,修改对象的属性不会触发UI更新。需要把整个对象重新赋值。
- build() 方法里不要写耗时操作:build() 是同步的,里面不能有网络请求或者文件读写。这些操作要放到
aboutToAppear()生命周期里。
我的建议:刚开始学ArkTS的时候,别急着写复杂页面。先拿几个简单的组件练手,比如写个计数器、待办列表。等你熟悉了声明式UI的思维模式,再去看官方文档,会发现很多东西都是相通的。
好了,ArkTS的入门就到这里。记住,语言只是工具,核心是声明式UI的思维方式。你写Kotlin的经验不会白费,只是换了一种表达方式而已。
公众号:蓝海资料掘金营,微信deep3321