基础入门
-
工程中,哪个目录保存代码文件?哪个目录保存资源文件?
① 代码文件:
entry/src/main/ets/pages② 资源文件:
entry/src/main/resources -
HarmonyOS 主要开发语言是什么?
① 新一代应用推荐优先采用 ArkUI eTS 语言开发
概念拓展与解释
-
代码文件目录:
entry/src/main/ets/pages- 在 HarmonyOS 的工程结构中,
ets目录主要存放基于方舟开发框架(ArkUI)的 eTS(Enhanced TypeScript) 代码,主要用于页面和组件的逻辑实现。 pages目录下通常存放项目的各个页面(类似于 Android 的Activity或Fragment),每个页面对应一个.ets文件。
- 在 HarmonyOS 的工程结构中,
-
资源文件目录:
entry/src/main/resources- 资源目录用于存放项目中的图片、字符串、布局、颜色、样式等静态资源文件。
- 这里的
resources目录相当于 Android 项目中的res目录,存放 app 所需的各种非代码静态资源。
-
HarmonyOS 主要开发语言
- HarmonyOS 目前主要支持 eTS(增强型 TypeScript) 作为 UI 和业务逻辑开发的主力语言,也可以使用 Java(主要用于传统 Ability 的扩展)和 C/C++(用于高性能原生开发)。
- 新一代应用推荐优先采用 ArkUI eTS 语言开发,语法类似 TypeScript,但专门针对华为的方舟编译器与分布式特性做了增强。
ArkUI eTS 和 ARK TS的区别
1. ArkUI eTS
-
全称:ArkUI Enhanced TypeScript
-
定位:HarmonyOS 新一代 UI 框架的主推开发语言。
-
特点:
- 基于 TypeScript 语法增强,专为 HarmonyOS 应用开发优化。
- 提供声明式 UI 编程体验,语法类似 React/Vue 等现代前端框架。
- 支持响应式数据绑定、组件化开发、丰富的UI组件库。
- 与华为方舟编译器(Ark Compiler)深度结合,具备更好的性能和分布式特性。
-
应用场景:主要用于开发 HarmonyOS 3.x 及以后版本的 ArkUI 应用(ArkUI Stage模型)。
2. ARK TS(ArkTS)
-
全称:Ark TypeScript(有时官方也简称 ArkTS)
-
定位:HarmonyOS/Ark Engine 的一套"运行时和编译时均支持"的 TypeScript 超集。
-
特点:
- 以 TypeScript 为基础,增加了一些 HarmonyOS/Ark 引擎特有的语法和运行时能力。
- 编译时能直接生成高效的字节码,提升运行效率。
- 既可以写 UI 层(和 ArkUI eTS 结合),也可以用来开发业务逻辑、后端服务甚至部分底层扩展。
- 适用于全栈开发与高性能需求。
-
应用场景:不限于 UI,ArkTS 也可以用于非界面业务逻辑(比如数据处理、服务开发)。
3. 总结二者关系
- ArkUI eTS 是 UI 框架 层面(你可以理解为"写界面用的")。
- ArkTS 更广,是 HarmonyOS 方舟生态下的"增强型 TypeScript",不仅能写 UI,也能写业务逻辑和服务。
- 实际开发时,你写 ArkUI eTS 页面,其实就是在用 ArkTS 语法+HarmonyOS 提供的 UI 组件和API。
- 也就是说:ArkUI eTS = ArkUI 框架 + ArkTS 语言能力。
形象类比
| 类别 | Android 生态 | HarmonyOS 生态 |
|---|---|---|
| UI 框架 | Jetpack Compose | ArkUI |
| UI语言/语法 | Kotlin/Java | ArkUI eTS (ArkTS) |
| 语言底层 | Java/Kotlin | ArkTS |
典型 ArkUI eTS 代码示例
typescript
@Entry
@Component
struct HelloWorld {
build() {
Text("Hello, ArkUI!")
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
}
这就是ArkUI eTS 写法,本质用的就是ArkTS语法。
变量和类型
使用变量存储不同类型的数据
数据类型:
-
文字信息 →
'字符串类型' (string) -
数据信息 →
数字类型 (number) -
状态信息 →
布尔类型 (boolean)- true
- false
TypeScript 官方建议
Always use
string,number,boolean(小写的类型),不要用大写的String、Number、Boolean。
string是基本类型(primitive type),性能好,语义明晰。String是一个对象类型(object),你可以写new String("abc"),但通常没必要。
数组:一次性保存多个同类型数据
数组也是容器,用来存储多个数据。
数组格式:
[数据1, 数据2, ......]
数组定义语法
typescript
let 数组名: 类型[] = [数据1, 数据2, 数据3, ......]
示例代码(TypeScript):
typescript
let titles: string[] = ['A', 'B', 'C']
-
上面数组
titles存储了三个字符串类型的数据(商品名)。 -
通过索引访问(下标从 0 开始):
titles[0]→'A'titles[1]→'B'titles[2]→'C'
对象
示例:
typescript
interface Goods {
title: string
price: number
}
let vase: Goods = {
title: '创意橘子花瓶',
price: 12.99
}
-
存储多个同类型数据用什么?存储多个不同类型数据用什么?
- 存储多个同类型数据:数组
- 存储多个不同类型数据:对象
-
对象的语法规则?
- 定义接口:
interface 接口名 {} - 定义对象:
let 对象名: 接口名 = {}
- 定义接口:
-
如何获取对象的属性值?
- 语法:
对象名.属性名
- 语法:
拓展理解
- 数组 适合保存一组类型相同的数据(如一组价格、一组商品名)。
- 对象 适合保存一个具体事物的多个不同类型的属性(如一个商品的名字和价格)。
- 接口(interface) 用于约束对象结构,让对象更规范,便于团队开发和类型检查。
- 属性访问 :对象的属性通过"点语法"访问,例如
vase.title、vase.price。
函数
typescript
function calc(r: number) {
return 2 * 3.14 * r
}
let c1: number = calc(5)
-
函数语法规则
-
定义函数
function 函数名(参数列表) {}其中参数列表里的是形参(形式参数)。
-
调用函数
函数名(数据列表)括号里的叫实参(实际参数)。
-
-
必须给函数设置参数和返回值吗?
- 非必须
拓展说明
-
形参:函数定义时括号里的变量名,用来接收调用时传入的值。
-
实参:函数调用时传入的实际数据。
-
返回值 :通过
return返回计算结果,可以没有返回值(即省略return或默认返回undefined)。 -
无参数/无返回值:
typescriptfunction hello() { console.log("Hello world!") } hello() -
有参数无返回值:
typescriptfunction printMsg(msg: string) { console.log(msg) } printMsg("Hi")
箭头函数
-
箭头函数的写法是?
typescript() => {}
代码示例:
typescript
let sum = (num1: number, num2: number) => {
return num1 + num2
}
拓展说明
-
**箭头函数(Arrow Function)**是 ES6 引入的一种简洁写法。
-
基本语法:
typescript(参数) => { 代码块 } -
没有参数时写作:
() => {}有一个参数时可以省略括号:
x => {}只有一行返回值时可以省略
{}和return:typescriptconst add = (a, b) => a + b -
箭头函数不会绑定自己的
this,适合回调和简短操作。
组件语法
-
鸿蒙界面布局的思路是什么?
先布局,再内容 -
组件的语法规则是什么?
- 容器组件:组件名
{} - 内容组件:组件名
()
例子(右上代码框):
tsColumn() { Text('one') Text('one') Text('one') } - 容器组件:组件名
-
Column、Row、Text 分别是什么作用?
- Column :内容换行排列(即垂直方向排列,每个子组件在下一行)。
- Row :内容在一行排列(即水平方向排列,每个子组件紧挨着在同一行)。
- Text :显示文本内容。
拓展说明
-
鸿蒙(HarmonyOS)ArkUI/Compose语法类似于 Flutter 和 Jetpack Compose,采用声明式 UI。
-
通常建议:先规划布局(Column/Row/Stack),再往里面填充内容组件(Text/Image/Button等) 。
-
常用布局组件:
Column() { ... }纵向排列内容Row() { ... }横向排列内容Stack() { ... }层叠排列内容(类似Android的FrameLayout)
-
语法上,花括号
{}里面可以写多行内容,相当于"容器"。
通用属性
-
如何给组件添加属性方法?
组件.属性()
- 例如:
Text('Hello').fontSize(18).width(100)
- 例如:
-
通用属性的使用范围是?
所有组件均可使用- 比如常见的尺寸、颜色、边距、背景色等属性,基本所有可视化组件都可以加。
-
width、height、backgroundColor 分别是什么意思?
- width → 宽度
- height → 高度
- backgroundColor → 背景色
拓展说明
-
组件属性的链式调用:在 ArkUI eTS、Flutter、Jetpack Compose 等现代声明式 UI 框架里,组件可以通过"点语法"链式设置多个属性,如:
tsText('内容') .width(200) .height(50) .backgroundColor('#FF0000') -
通用属性 :这些如尺寸、边框、对齐、背景色等属性,是几乎所有组件都能使用的,称为"通用属性"或"公共属性"。
-
属性调用格式:
组件.属性名(值)- 可以链式连续调用。
图片资源的使用
-
图像组件写法是什么?
scssImage(图像资源路径)- 例子:
Image($r('app.media.logo')) - 用于在页面上显示一张图片。
- 例子:
-
哪个目录可以存储图像资源?如何查找?
-
资源目录:
bashresources/base/media/ -
查询/引用方式:
bash$r('app.media.xx') -
说明:
resources/base/media/是 HarmonyOS(ArkUI/鸿蒙开发)应用工程的标准资源文件夹之一,专门用来存放图片、音频、视频等多媒体文件。 -
通过
$r('app.media.xx')的方式可以在代码中访问 media 目录下的资源文件,其中xx是具体的文件名(不带扩展名)。
-
拓展说明
-
Image 组件
ArkUI eTS/TS 里
Image()用于显示图片,括号里填写图片路径或引用资源ID。- 静态资源用法 :
Image($r('app.media.icon_avatar')) - 网络图片用法 :
Image('https://example.com/image.png')
- 静态资源用法 :
-
** <math xmlns="http://www.w3.org/1998/Math/MathML"> r ( ) 的作用 ∗ ∗ ' r() 的作用** ` </math>r()的作用∗∗'r()
是一个资源定位函数,用于获取项目中静态资源的引用ID。app.media.xx表示在media目录下名为xx` 的资源文件。 -
实际开发小技巧
- 图片等资源应统一放到
resources/base/media/,方便管理和维护。 - 引用图片资源时不要带扩展名,如
.png、.jpg,只写文件名即可。
- 图片等资源应统一放到
内外边距
1. 内外边距的作用是什么?
-
内边距(padding):拉开内容与组件边缘的距离
让内容不紧贴组件边框,常用于让文字、图片与容器边缘之间有"缓冲区"。
-
外边距(margin):拉开两个组件的距离
控制组件之间的空隙,防止它们挤在一起。
2. 如何设置内外边距的值?
-
单值 :四个方向间距相同
js.padding(数值) .margin(数值)例:
.padding(10)表示上下左右内边距都是10 -
对象 :四个方向间距不同
js.padding({ top: 10, bottom: 20, left: 30, right: 40 }) .margin({ top: 10, bottom: 20, left: 30, right: 40 })例:
top、bottom、left、right可分别设置。
拓展理解
- 内边距(padding) 用于内容与容器边界的距离,常用于让文字不贴边、图片有留白。
- 外边距(margin) 用于组件与其他组件的距离,常用于列表项、按钮之间的分隔。
- 二者可以配合使用,一个控制"内容到自己壳的距离",一个控制"自己与别人的距离"。
- 大部分UI框架(如 ArkUI、Flutter、React Native 等)都支持这种写法,理念基本一致。
边框属性
1. 边框属性是什么?
边框属性是指为组件添加可视化的边线(边框)的相关样式设置,常用于界面元素的分割、突出和美化。
组件设置边框的代码示例
js
组件
.border({
width: 粗细, // 边框宽度,如 1、2、4 等
color: 颜色, // 边框颜色,如 "#ff0000"、"red" 等
style: 线条样式, // 线条样式,如 "solid"(实线)、"dashed"(虚线)、"dotted"(点线)等
radius: 圆角 // 圆角半径,如 4、8、16 等,决定边框四角的弯曲程度
})
概念拓展
- width(宽度/粗细):控制边框的粗细程度。
- color(颜色):设置边框的颜色。
- style(样式):决定边框的线条形式(如实线/虚线/点线)。
- radius(圆角):用于让边框变成圆角矩形,提升界面圆润感。
典型用法举例
js
.border({
width: 2,
color: '#007AFF',
style: 'solid',
radius: 8
})
这行代码会让组件拥有一个2像素宽、蓝色、实线、圆角为8的边框。
适用场景
- 分隔内容区域
- 提示输入框获得焦点
- 突出显示按钮、卡片等UI元素
布局页面整体思路
1. 布局页面整体思路
先整体,再局部
先布局,再内容,后美化
- 布局设计时,要先搭建页面的整体结构,随后再细化每一个局部区域的排布。
- 优先确定整体布局(如主框架、主导航、主区域),再依次添加每一块的内容,最后进行样式和美化工作。
这种思路可以提升页面开发的条理性和维护性,也方便后期优化。
2. 可滚动的组件是什么?
代码示例:
js
List() {
ListItem() {}
}
.scrollBar(BarState.Off)
List:用于实现可滚动列表 ,可以容纳多个ListItem。ListItem:表示列表中的每一项。.scrollBar(BarState.Off):用于控制滚动条的显示状态(此处为关闭滚动条)。
拓展:
- 在 ArkUI、Flutter、React Native 等现代 UI 框架中,"可滚动组件"通常指支持滚动操作的容器,比如
ListView、ScrollView、LazyColumn等,主要用于内容项较多需要滚动浏览的场景。 - 滚动组件通常提供滚动条、滚动事件监听、懒加载等能力。
3. layoutWeight(数字) 作用是什么?
将外层组件剩余尺寸分成指定份数,当前组件占用对应的份数
layoutWeight常用于弹性布局中,用来分配剩余空间。- 例如在横向或纵向线性布局(如 Row/Column)下,
layoutWeight(2)表示当前组件会分得"总剩余空间的2份",假如有另一个组件layoutWeight(1),它就分1份,两者比例就是2:1。
举例说明:
- 如果父容器剩余300px空间,A组件
layoutWeight(2),B组件layoutWeight(1),则A占200px,B占100px。
4. 扩充组件安全区代码
js
组件() {
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
}
expandSafeArea用于自动处理安全区域(如刘海、圆角、底部虚拟导航栏) ,保证组件内容不会被系统区域遮挡。- 参数
SafeAreaType.SYSTEM表示基于系统安全区扩展。 [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]指定扩展的边界(顶部和底部)。
拓展说明:
- 在移动端开发中,合理利用安全区是保证UI自适应、兼容不同设备屏幕(如全面屏、刘海屏、圆角屏)的重要手段。
循环渲染
总结
-
循环渲染的作用是什么?
根据数组 数据重复渲染 UI 内容
-
循环渲染的语法是什么?
tsForEach(数组, (item: 类型, index: number) => { 组件 })
鸿蒙 ArkTS/JS 循环渲染概念拓展
1. 循环渲染的作用
- 在鸿蒙 ArkTS/JS UI 开发中,循环渲染 用于根据数组等集合的数据,批量生成和显示重复的界面内容。
- 典型场景:渲染列表(如联系人列表、商品列表、消息列表等)。
2. 鸿蒙中的 ForEach 语法解析
-
鸿蒙 ArkTS 提供了
ForEach组件,专门用于批量渲染。 -
语法如下:
tsForEach(数据源, (item: 类型, index: number) => { // 返回需要渲染的子组件,可以访问 item 和 index // 例如 Text(`${index + 1}: ${item.name}`) }) -
参数说明:
数据源:要遍历的数据集合(如数组)。item:遍历到的每一项数据。类型:该项数据的类型(可省略类型,TS更严谨)。index:当前项的下标(索引号)。
3. 例子(ArkTS 代码)
假设有个用户数组:
ts
@State users: Array<{ name: string, age: number }> = [
{ name: '小明', age: 18 },
{ name: '小红', age: 20 }
];
build() {
Column() {
ForEach(this.users, (user, index) => {
Row() {
Text(`${index + 1}. ${user.name},年龄:${user.age}`)
}
})
}
}
4. 本质理解
- ForEach 会根据你的数组数据,自动把回调函数里定义的组件批量渲染出来,这样就能轻松生成大量类似的 UI 结构。
- 当数组数据变化(比如新增、删除、修改),界面会自动更新,非常适合处理动态列表。
5. 和 React/Vue 区别
- React 用
.map,Vue 用v-for,鸿蒙用ForEach,核心思想都是"数据驱动视图",让数据和界面自动同步。
鸿蒙 ArkTS/JS V2 组件
1. 如何定义和使用 V2 状态?
- V2 状态管理是鸿蒙 ArkTS/JS(eTS)组件式开发(V2 组件模型)的核心特性。
- 用
@ComponentV2标记一个组件结构体(struct),在结构体内部用@Local声明本地状态变量。 - 变量声明格式如:
@Local num: number = 1 - 在组件内部可以通过
this.num访问和操作状态变量。 - 状态变化时,UI 会自动响应刷新。
typescript
@ComponentV2
struct Counter {
@Local count: number = 0
build() {
Row() {
Button("加1")
.onClick(() => {
this.count += 1
})
Text(`当前:${this.count}`)
}
}
}
示例:
typescript
build() {
Column() {
Row() {
Text('-')
.width(40)
.height(40)
.border({width: 1, color: '#999', radius: {topLeft: 3, bottomLeft:3}})
.textAlign(TextAlign.Center)
.onClick(() => {
if (this.num > 1) {
this.num--
}
})
Text(this.num.toString())
.width(40)
.height(40)
.textAlign(TextAlign.Center)
.border({width: {top: 1, bottom: 1}, color: '#999'})
.fontSize(18)
Text('+')
.width(40)
.height(40)
.border({width: 1, color: '#999', radius: {topRight: 3, bottomRight: 3}})
.textAlign(TextAlign.Center)
.onClick(() => {
this.num++
})
}
.padding(50)
}
.padding(20)
}
- V2 状态管理 :
@ComponentV2+@Local,用this.变量名访问。 - 点击事件绑定 :
.onClick(() => { /* 事件处理 */ })。
ArkTS/JS Builder 装饰器
-
@Builder装饰的函数作用是什么?封装 UI 元素,提升复用性
-
自定义构建函数如何定义和使用?
概念拓展与说明
1. @Builder 装饰器的作用
- @Builder 是 ArkTS/JS(鸿蒙 eTS)的一个装饰器,用于定义可复用的 UI 构建函数(也叫"构建器")。
- 用它封装经常使用的 UI 结构,可以像"积木"一样多次调用,减少重复代码,提升开发效率和组件复用性。
- 类似于 React 的函数组件、Flutter 的 Widget 工厂、Vue 的插槽函数等。
2. 如何定义和使用自定义构建函数
-
定义:
用
@Builder修饰一个函数,这个函数返回 UI 组件结构,可以带参数以支持灵活调用。typescript@Builder 自定义构建函数名(参数列表){ 要复用的组件结构 } @Builder CustomCard(title: string, content: string) { Column() { Text(title).fontSize(20) Text(content).fontSize(14) } } -
使用:
在组件内部,通过
this.自定义构建函数名(参数)来调用这个构建函数,实现多次渲染、复用。typescriptthis.自定义构建函数名(数据列表1) this.自定义构建函数名(数据列表2) this.CustomCard("标题A", "内容A") this.CustomCard("标题B", "内容B")
3. 实际应用场景举例
假如要在页面上多处展示类似的卡片组件,每个内容不同,就可以用 @Builder:
typescript
@Builder
InfoCard(name: string, age: number) {
Row() {
Text(`姓名: ${name}`)
Text(`年龄: ${age}`)
}
}
// 在主组件中多次调用
this.InfoCard("张三", 18)
this.InfoCard("李四", 20)
4. 总结一句话
@Builder就是让我们可以像写函数一样"批量生产"可复用的 UI 结构。
1. 循环渲染数据的思路是什么?
- 数组数据 → ForEach → 替换数据
拓展说明:
在 ArkTS/JS(eTS)开发中,常用 ForEach 组件来根据数组内容批量渲染 UI。例如有一个歌曲列表,需要显示每一首歌的信息,可以这样做:
typescript
ForEach(this.songList, (item, index) => {
// 这里渲染每一项UI,比如
Text(item.title)
})
替换数据:当数组的数据发生变化(如增删改),界面会自动刷新,做到数据驱动视图。
2. 控制播放状态的思路是什么?
- 播放状态组件(层叠) → 状态变量 @Local 播放索引 → 条件渲染播放状态组件 → 点击事件修改状态变量
拓展说明:
- 比如做一个音频播放器列表,只允许一首歌被标记为"正在播放"。
- 可以用一个
@Local状态变量(如playingIndex)来标记当前正在播放的那一项。 - 渲染每一项时判断:如果
index === playingIndex,就显示"正在播放"状态,否则显示普通状态。 - 当用户点击其它项时,更新
playingIndex,自动刷新UI。
伪代码示例:
typescript
@Local playingIndex: number = -1
ForEach(this.songList, (item, index) => {
Row() {
Text(item.title)
if (this.playingIndex === index) {
Text("正在播放")
}
Button("播放").onClick(() => {
this.playingIndex = index
})
}
})
3. 层叠布局组件是什么?
- Stack 容器组件
拓展说明:
Stack是鸿蒙 ArkTS/JS 用于层叠(绝对重叠)多个子组件的容器,适合实现类似"海报加按钮""图片加浮层"等复杂UI。- 子组件会按顺序从下到上层层堆叠。
示例代码:
typescript
Stack() {
Image('背景图')
Text('叠加在图片上的文字')
Button('悬浮按钮')
}
总结一句话
- 循环渲染:数据驱动、用 ForEach。
- 播放状态管理:用状态变量 + 条件渲染 + 事件驱动。
- 层叠布局:用 Stack 实现多组件重叠。
启动页导航跳转与布局对齐最佳实践
1. 生命周期钩子:aboutToAppear vs onAppear vs build
| 生命周期方法 | 触发时机 | 典型用途 | 注意事项 |
|---|---|---|---|
build() |
组件被首次实例化时 | 构建 UI 结构、声明子组件 | 只执行一次,不可做耗时操作;如果依赖异步结果,请使用状态变量触发重绘 |
aboutToAppear() |
组件即将挂载到可见树,但 UI 尚未真正可见 | 预加载数据、定时器、权限申请 | 如需在页面 真正 可见后再调接口,请选 onAppear() |
onAppear() |
组件已完成布局并显示到屏幕 | 动画、埋点、focus 控制 | 页面频繁进入退出时会多次触发 |
onReady(context) |
Navigation 容器内部可拿到 pathStack 等上下文时 |
保存导航栈引用、读取路由参数 | 如果仅做一次性导航初始化,可在这里完成 |
贴士 :
在启动页场景下,把 3 s 定时任务放在aboutToAppear()比放在build()更安全,可避免 UI 还没渲染完就先跳转导致白屏。
2. replacePathByName 与 pushPathByName 细节对比
| 特性 | pushPathByName |
replacePathByName |
|---|---|---|
| 导航栈行为 | 在栈顶 压入 新页面,旧页面仍保留 | 用新页面 替换 栈顶,旧页面被销毁 |
| 系统返回键 | 返回上一级(旧页面) | 直接退出或返回更早的页面 |
| 内存占用 | 多一次页面实例 | 较低,释放旧页面资源 |
| 动画 | 默认遵循平台 push 动画 | 默认遵循平台 replace/redirect 动画 |
| 典型场景 | 普通页面跳转、可返回 | 启动页→主页、登录页→主页、兼容"单实例"页面 |
| 可选参数 | (pageName, params?, animated = true) params 可传 JSON;animated = false 可关闭转场动画 |
同上 |
最佳实践:
- 登录/引导页 相对主页,建议用
replace,避免用户按返回键又回到登录页。- 普通详情页跳转列表页,用
push保留返回链路。
3. Stack 对齐与布局能力
| 属性 | 功能 | 取值示例 |
|---|---|---|
alignContent |
决定 子元素整体 在 Stack 的 主轴 + 交叉轴 上的对齐方式 |
TopStart, TopCenter, TopEnd, Center, BottomEnd... |
alignItems |
决定 每个子元素 在 交叉轴 上的单独对齐(若框架支持) | Start, Center, End |
direction |
堆叠方向(部分框架提供) | Vertical, Horizontal |
expandSafeArea |
是否覆盖状态栏/导航栏安全区域 | [SafeAreaType.SYSTEM]、自定义边缘 |
示例:
tsStack({ alignContent: Alignment.BottomCenter }) { ... }表示所有子组件整体右下角对齐;若要让单个子元素对齐不同位置,可在子元素上再套一个
Positioned或者子级Stack。
4. 计时跳转的两种常见写法
| 写法 | 说明 | 代码片段 |
|---|---|---|
| 手动定时器 | 使用 setTimeout(或 setInterval) |
setTimeout(() => nav.replacePathByName('Home'), 3000) |
| 动画/倒计时组件 | 借助内置 Ticker/AnimationController,结束回调里跳转 |
用于复杂动画、跳过按钮显示剩余秒数 |
5. 常见坑及建议
- 白屏问题 :若
replace在首屏网络请求前执行,可出现短暂空白 ------ 可给首页加骨架屏或延迟replace直到数据准备完毕。 - 多次跳转 :启动页 + 跳过按钮 + 网络回调,多处可能调用
replace/push,请在回调前判断pageStack.current.name,或用标记变量防抖。 - 内存泄漏 :离开页面时记得
clearTimeout、停止动画,或在aboutToDisappear()里做资源释放。
总结
aboutToAppear()适合做 一次性 延迟逻辑或预取工作;replacePathByName与pushPathByName最大区别在返回栈行为;Stack的alignContent决定整体子元素对齐,多配合Positioned/Padding获得灵活布局;- 合理管理定时器与导航可避免白屏、跳转错乱等问题。
全局共享 NavPathStack
-
非 Navigation 子页如何实现页面跳转?
- 全局共享 NavPathStack
- AppStorageV2:可以提供状态变量在应用级全局共享的能力
-
如何使用 AppStorageV2?
AppStorageV2.connect( NavPathStack, // 类型 (Type) 'navStack', // key () => new NavPathStack() // 初始化值 (Factory) )!
1. 为什么要"全局共享 NavPathStack"?
在 ArkUI/Stage 模式中,Navigation 组件自身会维护一棵页面栈。但当你在 非 Navigation 子组件 (例如 Dialog、Service 侧滑页、Overlay 层)里需要跳转其它界面时,就无法直接拿到父级导航器。
将 NavPathStack 通过 AppStorageV2 注册为 全局单例 后,任何位置都可安全地:
ts
AppStorageV2.get<NavPathStack>('navStack')?.push('DetailPage');
优势:
- 解耦:子组件不再硬依赖父级
Navigation。- 生命周期可控:全局唯一栈实例随 app 存活,避免多处重复创建。
2. AppStorageV2.connect 的 3 个参数
| 序号 | 作用 | 典型写法 |
|---|---|---|
1. 类型 (Type) |
用于类型推断,IDE 自动补全 | NavPathStack |
| 2. key | 全局唯一字符串标识 | 'navStack' |
| 3. 初始化函数 | 首次取值时执行,返回默认实例 | () => new NavPathStack() |
3. 常见用法示例
ts
// ① 全局初始化(例如在 @Entry 首页面)
AppStorageV2.connect(NavPathStack, 'navStack', () => new NavPathStack());
// ② 任意子组件中调用
function gotoProfile(userId: string) {
const stack = AppStorageV2.get<NavPathStack>('navStack');
stack?.push({
name: 'ProfilePage',
params: { id: userId }
});
}
// ③ 支持返回
function backToHome() {
const stack = AppStorageV2.get<NavPathStack>('navStack');
while (stack && stack.depth > 1) {
stack.pop();
}
}
4. 实战注意事项
- 统一管理路径常量
推荐定义enum RouteNames,避免硬编码字符串导致的跳转失败。 - 线程安全
UI 线程以外访问时,务必派发到主线程,保证栈操作与渲染同步。 - 栈深度监控
若频繁跳转,考虑在push()前检测depth,超阈值时清理无用页面。 - 模块化项目
每个 Feature 可以把自身路由注册到一个RouteRegistry,再由公共navStack调度,方便动态化加载。
5. 何时不适合用全局 NavPathStack?
- 强耦合导航逻辑 :若某模块需要独立返回栈(如登录流程),局部
Navigation仍是更干净的做法。 - 多窗口 / 多任务模式:不同窗口应持有各自的 NavPathStack,避免状态混淆。
总结
把
NavPathStack暴露为应用级状态,是在非 Navigation 子页发起路由跳转的简单又可靠方案;利用
AppStorageV2.connect()创建单例后,任何组件都可随取随用,同时保持类型安全与生命周期可控。
课程源码
补全了除AI生成的代码的全部源码: 黑马云音乐源码