基础入门
-
工程中,哪个目录保存代码文件?哪个目录保存资源文件?
① 代码文件:
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生成的代码的全部源码: 黑马云音乐源码