本文将从一个前端开发者的角度出发,速通鸿蒙 Next 开发的方方面面,并最终开发一个 Todo List 小实例。
简介
首先,鸿蒙使用 ArkTS
作为原生开发语言。如果你熟悉 TypeScript
编程语言,那基本上可以无缝过渡,因为 ArkTS 并不是一门全新的语言,而是在 TypeScript 基础上进行扩展的。这意味着我们可以跳过学习新语言的阶段,只需学习鸿蒙的 UI 框架 ArkUI
。
类似于 React,ArkUI 框架采用声明式的开发范式来描述 UI,并且内置了完善的状态管理机制,无需像 React 那样面对各种混乱的第三方状态库。
鸿蒙内置组件的布局设计基于 CSS
的概念,包括 margin
、padding
、flex
、grid
、栅格系统和媒体查询等,这些都是前端开发者所熟悉的。
鸿蒙 Next 提供了完整的开发、调试、测试和发布一站式 IDE。如果你之前使用过 IntelliJ IDEA,那么对你来说将是无缝衔接的,因为鸿蒙的 DevEco 是基于 IntelliJ IDEA Community
进行深度定制的。但如果你跟我一样是 Neovim
或者 VSCode
的死忠粉的话,也没有关系 DevEco
其实是很好上手的。
IDE 介绍
工欲善其事,必先利其器,我们先看看鸿蒙的 IDE 怎么用
DevEco-Studio 安装
目前提供3个版本可供下载
- Windows(64-bit)
- Mac(X86)
- Mac(ARM)
注意目前版本需要 Node 18.x
环境,前端开发者建议安装 nvm,事先切换好 Node 版本。
安装好 nvm 后
nvm install 18.14.1
nvm use 18.14.1
node -v
这样你在安装 DevEco 的时候就可以选择 Local 的 Node 环境了,如果你本地没有 Node,也可以选择全新安装
接下来如果一切顺利,在 Diagnose
界面就会看到满屏的对号,表示安装成功了。
我相信你能摸索着创建一个 Hello Wrold 项目
接下来会看到树形列表中默认创建了大量的文件,跟我刚开始一样,不知如何下手,经过研究发现很多文件是有两份的,一个是模块级的,一个是整个应用级的。
为了清楚起见,我画了一张图,图中左侧列出的文件,都是应用和模块的两个版本的。
整个 entry
目录叫做一个 Module
,该目录会编译为一个 .hap
为后缀的文件,HAP 包。
等应用最终上架时,会打包成 .app
为扩展名的文件,上传到华为商店。
Module
不只有 entry
类型的,还有其他类型的,简单起见,我还是总结一张图:
初看是有点头大,其实作为入门,只需要关注的 entry
模块,其他 Module
类型可等到深入开发时再去文档了解。
entry
目录下有一个 src/main/ets/pages/index.ets
文件,这是用户看到的第一个页面,我们先把该文件打开看个大概,后边编程语言的部分会详细介绍对应语法。
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}
第一行的 @Entry
装饰器表明这是应用的入口,中间 build()
方法返回的就是整个声明式UI的页面结构。
翻译过来就是一个满高的 Row 组件之中放了一个满宽的 Column 组件,里边放了一个 50 大小文本组件。
右上角选中 previewer
,点击 run
按钮即可运行,并预览效果。
输出效果
这就是整个开发流程了,刚才的代码怎么看着这么眼熟,是 TypeScript ?
编程语言
鸿蒙的主要开发语言是 ArkTS(.ets 文件)。看着眼熟是因为它是 TypeScript 的超集,基本上就是 TS 代码,最大的区别或者说特点,就是在编译时对静态类型的检查和分析做了增强,并对一些动态特性做了少量的限制。这使得程序在运行时类型都是已知的,减少了运行时 bug 并提升了程序性能。
比如,强制类型不允许使用 any
或 unknown
类型。也不能使用 obj as any
之类的语法动态给对象添加属性和方法,更不能在运行时使用 delete
删除属性或方法。在某些需要 any 类型的情况下,建议使用 Record\<string, Object>
类型。
编译器默认打开了 TypeScript 的一些严格模式,比如 strictPropertyInitialization
,要求强制给定初始值。strictNullChecks
强制进行空值安全检查等。
总之,你能想到的运行时的动态类型特性都会被限制,都尽量不要使用。更多详细的语法规则可以参考官方文档中关于《从 TypeScript 到 ArkTS 的适配规则》的文章,内容非常详细。实际上,在开发过程中,DevEco Studio 会提供很好的错误报告信息,因此你可以先不必了解这些语法规则,等到遇到问题时再去查询。
UI框架
ArkUI 框架是基于 ArkTS 的UI 框架,使用声明式的开发范式,数据驱动 UI 更新,并且提供了页面级路由导航等。
在页面布局方面提供了多种媒体查询,比如
- 设备类型
- 窗口宽高监听
- 折叠屏状态
- 横竖屏查询
统一了单位,比如
vp
虚拟像素fp
字体像素,用户端的设置会乘以系数1fp = 1vp * scale
并且提供了多种栅格系统,窗口栅格会根据容器宽度,自动匹配栅格数量
栅格 | size | 宽度 | 设备 |
---|---|---|---|
4格 | small | 360~600 | 手机竖屏 |
8格 | medium | 600~840 | 手机横屏,pad 竖屏,折叠屏 |
12格 | large | 840~1440 | pad 横屏,2in1 |
12格 | x-large | 1440~ | 全屏 |
需要注意的是,目前稳定主推的应用模型叫做Stage模型 ,如果你在学习的过程中看到FA模型,那就是就是旧版教程,可以不用看了。
光说不练是假把式,下边我们在代码层面了解一下如何声明 UI
声明式UI 描述
声明式 UI 的描述方式如下
Column() {
Text('item 1')
Divider()
Text('item 2')
}
Column 是容器组件,所以后边带{}
,里边包含子组件,非容器组件则无需{}
给组件配置属性通常用链式调用的方法
Text("hello").fontSize(20).fontColor(Color.Red).fontWeight(FontWeight.Bold);
为了更加清晰,通常会写成这种格式
Text("hello")
.fontSize(20)
.fontColor(Color.Red)
.fontWeight(FontWeight.Bold);
添加事件处理
Button("Click me").onClick(() => {
this.myText = "ArkUI";
});
装饰器
ArkUI 中大量的使用的装饰器,包括我们之前看到的 @entry
表示入口,再看一个最简单的自定义组件:
ArkUI 中用 @Component
装饰的 struct
结构代表自定义组件。
@Component
struct MyComponent {
@State message: string = 'Hello, World!';
build() {
// 在 build 函数里返回 UI 描述
}
}
目前流行数据驱动 UI 的编程范式,所谓 UI = f(State)
, 少不了状态,
ArkUI 中用 @State
装饰器来声明状态,Parent 可以直接覆盖 Child State
@Component
struct Parent {
build() {
Column() {
// 父组件覆盖State
MyComponent({ message:"hi" })
}
}
}
和 React 中的 State 类似,状态的变化可以引起 UI 更新,但注意这个状态不是 immutable 的,UI 是否可以观察到状态的变化要看数据类型,具体要参考详细的文档。
下边是典型的事件处理中修改状态,引起 UI 刷新的例子:
@Component
export struct HelloComponent {
@State message: string = 'Hello, World!';
build() {
Row() {
Text(this.message)
.onClick(() => {
// 基础类型的状态变量 message 改变驱动 UI 刷新,
// UI从'Hello, World!'刷新为'Hello, ArkUI!'
this.message = 'Hello, ArkUI!';
})
}
}
}
@State
只是组件内部的状态。如果想在状态更改时引发 Child 组件的更新,就要了解 @Props
装饰器了
@Props
用于接收 Parent 组件的更新,给接收端属性前加上 @Props
装饰器后,就很类似 React 中的 props 传递了,不同的是 @Props
属性自身改变也会引起 UI 更新,类似 React 的 props 和 state 的结合体,看以下例子:
@Component
export struct ChildComponent {
@Prop message: string;
build() {
Row() {
Text(this.message)
.onClick(()=>{
// 本身修改 Props 也会引起重绘
this.message += " !"
})
}
}
}
除了单向数据流,ArkUI 还提供了双向数据绑定的装饰器 @Link
,
跨层级共享数据的 @Provide
和 @Consume
装饰器有些类似 react 中的 useContext
。
画了个图总结一下,可以根据你的需要用的时候再去查文档。
一个实例
今天做一个学习新语言最常见的简易 ToDo List,请看下边代码,包含了详细注释
// 引入其他组件
import Item from '../ui/Item'
@Entry
@Component
struct Index {
// 当前文本输入框输入的文字
@State todo: string = '';
// 整个列表的状态数据
@State list: Array<string> = [
"学习鸿蒙开发",
"沟通外包",
"看剧放松"
];
build() {
// Flex 布局,纵向
Flex({ direction: FlexDirection.Column, }) {
// 增加一个标题文本
Text("待办事项")// .border({ width: 1 })
.width("100%")
.fontSize(28)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Start)
.margin({ bottom: 20 })
// 文本输入框,用于添加新待办事项
TextInput({ text: this.todo, placeholder: "请输入" })
.width("100%")
.height(45)
.enterKeyType(EnterKeyType.Done)
.placeholderColor(Color.Gray)
.margin({ bottom: 20 })
.onChange((value) => {
// 文字修改则更新状态,并绑定状态,使之变为受控组件
this.todo = value;
})
.onSubmit((value) => {
// 回车时触发,填进列表
console.log(String(value))
this.list.push(this.todo)
this.todo = ''
})
// 列表组件, 内部要使用 ForEach 渲染 ListItem 项
List({ space: 20 }) {
ForEach(this.list, (item: string) => {
ListItem() {
// ListItem 中包装了自定义组件 Item,见 ui/Item.ets
Item({ content: item })
}.width('100%')
}, (item: string, i) => i + item)
}
.flexGrow(1)
// 列表拖拽默认会有弹性特效,取消掉
.edgeEffect(EdgeEffect.None)
}
.padding(18)
.width('100%')
.height('100%')
.backgroundColor('#dddddd')
}
}
自定义列表项放入另一个目录 src/main/ets/ui/Item.ets
@Component
export default struct Item {
private content?: string;
@State isComplete: boolean = false;
@Builder
labelIcon(icon: Resource) {
Image(icon)
.objectFit(ImageFit.Contain)
.width(28)
.height(28)
.margin(20)
}
build() {
Row() {
// 条件渲染
if (this.isComplete) {
// 图标路径 entry/src/main/resources/base/media/ic_ok.png
this.labelIcon($r('app.media.ic_ok'));
} else {
// 图标路径 entry/src/main/resources/base/media/ic_default.png
this.labelIcon($r('app.media.ic_default'));
}
Text(this.content)
.fontSize(20)
.fontWeight(500)
.opacity(this.isComplete ? 0.4 : 1.0)
.decoration({ type: this.isComplete ? TextDecorationType.LineThrough : TextDecorationType.None })
}
.borderRadius(12)
.backgroundColor("#FFFFFF")
.width("100%")
.height("64vp")
.onClick(() => {
this.isComplete = !this.isComplete;
})
}
}
在模拟器中的显示效果
结语
通过上边的学习,可以看出相比于安卓的苹果两大系统,鸿蒙的开发相对于前端开发者来说友好得多。
在如此低迷的经济环境下,衷心希望鸿蒙系统在市场上可以取得大成功,给我们前端开发仔开辟一条新的赛道。
最后
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。
鸿蒙HarmonyOS Next全套学习资料←点击领取!(安全链接,放心点击)
这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了**(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)**技术知识点。
希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
鸿蒙(HarmonyOS NEXT)最新学习路线
有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类...等知识点。
获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料
HarmonyOS Next 最新全套视频教程
《鸿蒙 (OpenHarmony)开发基础到实战手册》
OpenHarmony北向、南向开发环境搭建
《鸿蒙开发基础》
- ArkTS语言
- 安装DevEco Studio
- 运用你的第一个ArkTS应用
- ArkUI声明式UI开发
- .......
《鸿蒙开发进阶》
- Stage模型入门
- 网络管理
- 数据管理
- 电话服务
- 分布式应用开发
- 通知与窗口管理
- 多媒体技术
- 安全技能
- 任务管理
- WebGL
- 国际化开发
- 应用测试
- DFX面向未来设计
- 鸿蒙系统移植和裁剪定制
- ......
《鸿蒙进阶实战》
- ArkTS实践
- UIAbility应用
- 网络案例
- ......
大厂面试必问面试题
鸿蒙南向开发技术
鸿蒙APP开发必备
鸿蒙生态应用开发白皮书V2.0PDF
获取以上完整鸿蒙HarmonyOS学习资料,请点击→****
总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。