关于《黑马鸿蒙5.0零基础入门》课程的总结

321 阅读20分钟

基础入门

  1. 工程中,哪个目录保存代码文件?哪个目录保存资源文件?

    ① 代码文件:entry/src/main/ets/pages
    ② 资源文件:entry/src/main/resources

  2. HarmonyOS 主要开发语言是什么?

    ① 新一代应用推荐优先采用 ArkUI eTS 语言开发


概念拓展与解释

  1. 代码文件目录:entry/src/main/ets/pages

    • 在 HarmonyOS 的工程结构中,ets 目录主要存放基于方舟开发框架(ArkUI)的 eTS(Enhanced TypeScript) 代码,主要用于页面和组件的逻辑实现。
    • pages 目录下通常存放项目的各个页面(类似于 Android 的 ActivityFragment),每个页面对应一个 .ets 文件。
  2. 资源文件目录:entry/src/main/resources

    • 资源目录用于存放项目中的图片、字符串、布局、颜色、样式等静态资源文件。
    • 这里的 resources 目录相当于 Android 项目中的 res 目录,存放 app 所需的各种非代码静态资源。
  3. HarmonyOS 主要开发语言

    • HarmonyOS 目前主要支持 eTS(增强型 TypeScript) 作为 UI 和业务逻辑开发的主力语言,也可以使用 Java(主要用于传统 Ability 的扩展)和 C/C++(用于高性能原生开发)。
    • 新一代应用推荐优先采用 ArkUI eTS 语言开发,语法类似 TypeScript,但专门针对华为的方舟编译器与分布式特性做了增强。

ArkUI eTSARK 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 eTSUI 框架 层面(你可以理解为“写界面用的”)。
  • ArkTS 更广,是 HarmonyOS 方舟生态下的“增强型 TypeScript”,不仅能写 UI,也能写业务逻辑和服务
  • 实际开发时,你写 ArkUI eTS 页面,其实就是在用 ArkTS 语法+HarmonyOS 提供的 UI 组件和API。
  • 也就是说:ArkUI eTS = ArkUI 框架 + ArkTS 语言能力

形象类比
类别Android 生态HarmonyOS 生态
UI 框架Jetpack ComposeArkUI
UI语言/语法Kotlin/JavaArkUI eTS (ArkTS)
语言底层Java/KotlinArkTS

典型 ArkUI eTS 代码示例

@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(小写的类型),不要用大写的 StringNumberBoolean

  • string 是基本类型(primitive type),性能好,语义明晰。
  • String 是一个对象类型(object),你可以写 new String("abc"),但通常没必要。

数组:一次性保存多个同类型数据

数组也是容器,用来存储多个数据。

数组格式:
[数据1, 数据2, ……]


数组定义语法

let 数组名: 类型[] = [数据1, 数据2, 数据3, ……]

示例代码(TypeScript):

let titles: string[] = ['A', 'B', 'C']

  • 上面数组 titles 存储了三个字符串类型的数据(商品名)。

  • 通过索引访问(下标从 0 开始):

    • titles[0]'A'
    • titles[1]'B'
    • titles[2]'C'

对象

示例:

interface Goods {
  title: string
  price: number
}

let vase: Goods = {
  title: '创意橘子花瓶',
  price: 12.99
}

  1. 存储多个同类型数据用什么?存储多个不同类型数据用什么?

    • 存储多个同类型数据:数组
    • 存储多个不同类型数据:对象
  2. 对象的语法规则?

    • 定义接口:interface 接口名 {}
    • 定义对象:let 对象名: 接口名 = {}
  3. 如何获取对象的属性值?

    • 语法:对象名.属性名

拓展理解

  • 数组 适合保存一组类型相同的数据(如一组价格、一组商品名)。
  • 对象 适合保存一个具体事物的多个不同类型的属性(如一个商品的名字和价格)。
  • 接口(interface) 用于约束对象结构,让对象更规范,便于团队开发和类型检查。
  • 属性访问:对象的属性通过“点语法”访问,例如 vase.titlevase.price

函数

function calc(r: number) {
  return 2 * 3.14 * r
}

let c1: number = calc(5)

  1. 函数语法规则

    • 定义函数
      function 函数名(参数列表) {}

      其中参数列表里的是形参(形式参数)。

    • 调用函数
      函数名(数据列表)

      括号里的叫实参(实际参数)。

  2. 必须给函数设置参数和返回值吗?

    • 非必须

拓展说明

  • 形参:函数定义时括号里的变量名,用来接收调用时传入的值。

  • 实参:函数调用时传入的实际数据。

  • 返回值:通过 return 返回计算结果,可以没有返回值(即省略 return 或默认返回 undefined)。

  • 无参数/无返回值

    function hello() {
      console.log("Hello world!")
    }
    hello()
    
  • 有参数无返回值

    function printMsg(msg: string) {
      console.log(msg)
    }
    printMsg("Hi")
    

箭头函数

  1. 箭头函数的写法是?

    () => {}
    

代码示例:

let sum = (num1: number, num2: number) => {
  return num1 + num2
}

拓展说明

  • **箭头函数(Arrow Function)**是 ES6 引入的一种简洁写法。

  • 基本语法:

    (参数) => { 代码块 }
    
  • 没有参数时写作:() => {}
    有一个参数时可以省略括号:x => {}
    只有一行返回值时可以省略 {}return

    const add = (a, b) => a + b
    
  • 箭头函数不会绑定自己的 this,适合回调和简短操作。

组件语法

  1. 鸿蒙界面布局的思路是什么?
    先布局,再内容

  2. 组件的语法规则是什么?

    • 容器组件:组件名{}
    • 内容组件:组件名()
      例子(右上代码框):
    Column() {
      Text('one')
      Text('one')
      Text('one')
    }
    
  3. Column、Row、Text 分别是什么作用?

    • Column:内容换行排列(即垂直方向排列,每个子组件在下一行)。
    • Row:内容在一行排列(即水平方向排列,每个子组件紧挨着在同一行)。
    • Text:显示文本内容。

拓展说明

  • 鸿蒙(HarmonyOS)ArkUI/Compose语法类似于 Flutter 和 Jetpack Compose,采用声明式 UI

  • 通常建议:先规划布局(Column/Row/Stack),再往里面填充内容组件(Text/Image/Button等)

  • 常用布局组件:

    • Column() { ... } 纵向排列内容
    • Row() { ... } 横向排列内容
    • Stack() { ... } 层叠排列内容(类似Android的FrameLayout)
  • 语法上,花括号 {} 里面可以写多行内容,相当于“容器”。

通用属性

  1. 如何给组件添加属性方法?
    组件.属性()

    • 例如:Text('Hello').fontSize(18).width(100)
  2. 通用属性的使用范围是?
    所有组件均可使用

    • 比如常见的尺寸、颜色、边距、背景色等属性,基本所有可视化组件都可以加。
  3. width、height、backgroundColor 分别是什么意思?

    • width → 宽度
    • height → 高度
    • backgroundColor → 背景色

拓展说明

  • 组件属性的链式调用:在 ArkUI eTS、Flutter、Jetpack Compose 等现代声明式 UI 框架里,组件可以通过“点语法”链式设置多个属性,如:

    Text('内容')
      .width(200)
      .height(50)
      .backgroundColor('#FF0000')
    
  • 通用属性:这些如尺寸、边框、对齐、背景色等属性,是几乎所有组件都能使用的,称为“通用属性”或“公共属性”。

  • 属性调用格式

    • 组件.属性名(值)
    • 可以链式连续调用。

图片资源的使用

  1. 图像组件写法是什么?

    Image(图像资源路径)
    
    • 例子:Image($r('app.media.logo'))
    • 用于在页面上显示一张图片。
  2. 哪个目录可以存储图像资源?如何查找?

    • 资源目录:

      resources/base/media/
      
    • 查询/引用方式:

      $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')
  • **r()的作用r() 的作用** `r() 是一个资源定位函数,用于获取项目中静态资源的引用ID。app.media.xx表示在media目录下名为xx` 的资源文件。

  • 实际开发小技巧

    • 图片等资源应统一放到 resources/base/media/,方便管理和维护。
    • 引用图片资源时不要带扩展名,如 .png.jpg,只写文件名即可。

内外边距

1. 内外边距的作用是什么?

  • 内边距(padding):拉开内容与组件边缘的距离

    让内容不紧贴组件边框,常用于让文字、图片与容器边缘之间有“缓冲区”。

  • 外边距(margin):拉开两个组件的距离

    控制组件之间的空隙,防止它们挤在一起。


2. 如何设置内外边距的值?

  • 单值:四个方向间距相同

    .padding(数值)
    .margin(数值)
    

    例:.padding(10) 表示上下左右内边距都是10

  • 对象:四个方向间距不同

    .padding({ top: 10, bottom: 20, left: 30, right: 40 })
    .margin({ top: 10, bottom: 20, left: 30, right: 40 })
    

    例:topbottomleftright 可分别设置。


拓展理解

  • 内边距(padding) 用于内容与容器边界的距离,常用于让文字不贴边、图片有留白。
  • 外边距(margin) 用于组件与其他组件的距离,常用于列表项、按钮之间的分隔。
  • 二者可以配合使用,一个控制“内容到自己壳的距离”,一个控制“自己与别人的距离”。
  • 大部分UI框架(如 ArkUI、Flutter、React Native 等)都支持这种写法,理念基本一致。

边框属性

1. 边框属性是什么?

边框属性是指为组件添加可视化的边线(边框)的相关样式设置,常用于界面元素的分割、突出和美化。

组件设置边框的代码示例

组件
  .border({
    width: 粗细,      // 边框宽度,如 1、2、4 等
    color: 颜色,      // 边框颜色,如 "#ff0000"、"red" 等
    style: 线条样式,  // 线条样式,如 "solid"(实线)、"dashed"(虚线)、"dotted"(点线)等
    radius: 圆角      // 圆角半径,如 4、8、16 等,决定边框四角的弯曲程度
  })

概念拓展

  • width(宽度/粗细):控制边框的粗细程度。
  • color(颜色):设置边框的颜色。
  • style(样式):决定边框的线条形式(如实线/虚线/点线)。
  • radius(圆角):用于让边框变成圆角矩形,提升界面圆润感。

典型用法举例

.border({
  width: 2,
  color: '#007AFF',
  style: 'solid',
  radius: 8
})

这行代码会让组件拥有一个2像素宽、蓝色、实线、圆角为8的边框。

适用场景

  • 分隔内容区域
  • 提示输入框获得焦点
  • 突出显示按钮、卡片等UI元素

布局页面整体思路

1. 布局页面整体思路

先整体,再局部
先布局,再内容,后美化

  • 布局设计时,要先搭建页面的整体结构,随后再细化每一个局部区域的排布。
  • 优先确定整体布局(如主框架、主导航、主区域),再依次添加每一块的内容,最后进行样式和美化工作。

这种思路可以提升页面开发的条理性和维护性,也方便后期优化。


2. 可滚动的组件是什么?

代码示例:

List() {
    ListItem() {}
}
.scrollBar(BarState.Off)
  • List:用于实现可滚动列表,可以容纳多个 ListItem
  • ListItem:表示列表中的每一项。
  • .scrollBar(BarState.Off):用于控制滚动条的显示状态(此处为关闭滚动条)。

拓展:

  • 在 ArkUI、Flutter、React Native 等现代 UI 框架中,“可滚动组件”通常指支持滚动操作的容器,比如 ListViewScrollViewLazyColumn 等,主要用于内容项较多需要滚动浏览的场景。
  • 滚动组件通常提供滚动条、滚动事件监听、懒加载等能力。

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. 扩充组件安全区代码

组件() {
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
}
  • expandSafeArea 用于自动处理安全区域(如刘海、圆角、底部虚拟导航栏) ,保证组件内容不会被系统区域遮挡。
  • 参数SafeAreaType.SYSTEM表示基于系统安全区扩展。
  • [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM]指定扩展的边界(顶部和底部)。

拓展说明:

  • 在移动端开发中,合理利用安全区是保证UI自适应、兼容不同设备屏幕(如全面屏、刘海屏、圆角屏)的重要手段。

循环渲染

总结

  1. 循环渲染的作用是什么?

    根据数组数据重复渲染 UI 内容

  2. 循环渲染的语法是什么?

    ForEach(数组, (item: 类型, index: number) => {
        组件
    })
    

鸿蒙 ArkTS/JS 循环渲染概念拓展

1. 循环渲染的作用

  • 在鸿蒙 ArkTS/JS UI 开发中,循环渲染用于根据数组等集合的数据,批量生成和显示重复的界面内容
  • 典型场景:渲染列表(如联系人列表、商品列表、消息列表等)。

2. 鸿蒙中的 ForEach 语法解析

  • 鸿蒙 ArkTS 提供了 ForEach 组件,专门用于批量渲染

  • 语法如下:

    ForEach(数据源, (item: 类型, index: number) => {
        // 返回需要渲染的子组件,可以访问 item 和 index
        // 例如
        Text(`${index + 1}: ${item.name}`)
    })
    
  • 参数说明:

    • 数据源:要遍历的数据集合(如数组)。
    • item:遍历到的每一项数据。
    • 类型:该项数据的类型(可省略类型,TS更严谨)。
    • index:当前项的下标(索引号)。

3. 例子(ArkTS 代码)

假设有个用户数组:

@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 会自动响应刷新。
@ComponentV2
struct Counter {
  @Local count: number = 0

  build() {
    Row() {
      Button("加1")
        .onClick(() => {
          this.count += 1
        })
      Text(`当前:${this.count}`)
    }
  }
}

示例:

 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 组件结构,可以带参数以支持灵活调用。

    @Builder
    自定义构建函数名(参数列表){
        要复用的组件结构
    }
    
    @Builder
    CustomCard(title: string, content: string) {
      Column() {
        Text(title).fontSize(20)
        Text(content).fontSize(14)
      }
    }
    
  • 使用:
    在组件内部,通过 this.自定义构建函数名(参数) 来调用这个构建函数,实现多次渲染、复用。

    this.自定义构建函数名(数据列表1)
    this.自定义构建函数名(数据列表2)
    
    this.CustomCard("标题A", "内容A")
    this.CustomCard("标题B", "内容B")
    

3. 实际应用场景举例

假如要在页面上多处展示类似的卡片组件,每个内容不同,就可以用 @Builder

@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。例如有一个歌曲列表,需要显示每一首歌的信息,可以这样做:

ForEach(this.songList, (item, index) => {
  // 这里渲染每一项UI,比如
  Text(item.title)
})

替换数据:当数组的数据发生变化(如增删改),界面会自动刷新,做到数据驱动视图。


2. 控制播放状态的思路是什么?

  • 播放状态组件(层叠)状态变量 @Local 播放索引条件渲染播放状态组件点击事件修改状态变量

拓展说明:

  • 比如做一个音频播放器列表,只允许一首歌被标记为“正在播放”。
  • 可以用一个 @Local 状态变量(如 playingIndex)来标记当前正在播放的那一项。
  • 渲染每一项时判断:如果 index === playingIndex,就显示“正在播放”状态,否则显示普通状态。
  • 当用户点击其它项时,更新 playingIndex,自动刷新UI。

伪代码示例:

@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。
  • 子组件会按顺序从下到上层层堆叠。

示例代码:

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. replacePathByNamepushPathByName 细节对比

特性pushPathByNamereplacePathByName
导航栈行为在栈顶 压入 新页面,旧页面仍保留用新页面 替换 栈顶,旧页面被销毁
系统返回键返回上一级(旧页面)直接退出或返回更早的页面
内存占用多一次页面实例较低,释放旧页面资源
动画默认遵循平台 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]、自定义边缘

示例

Stack({ alignContent: Alignment.BottomCenter }) { … }

表示所有子组件整体右下角对齐;若要让单个子元素对齐不同位置,可在子元素上再套一个 Positioned 或者子级 Stack


4. 计时跳转的两种常见写法

写法说明代码片段
手动定时器使用 setTimeout(或 setIntervalsetTimeout(() => nav.replacePathByName('Home'), 3000)
动画/倒计时组件借助内置 Ticker/AnimationController,结束回调里跳转用于复杂动画、跳过按钮显示剩余秒数

5. 常见坑及建议

  1. 白屏问题:若 replace 在首屏网络请求前执行,可出现短暂空白 —— 可给首页加骨架屏或延迟 replace 直到数据准备完毕。
  2. 多次跳转:启动页 + 跳过按钮 + 网络回调,多处可能调用 replace/push,请在回调前判断 pageStack.current.name,或用标记变量防抖。
  3. 内存泄漏:离开页面时记得 clearTimeout、停止动画,或在 aboutToDisappear() 里做资源释放。

总结

  • aboutToAppear() 适合做 一次性 延迟逻辑或预取工作;
  • replacePathByNamepushPathByName 最大区别在返回栈行为;
  • StackalignContent 决定整体子元素对齐,多配合 Positioned/Padding 获得灵活布局;
  • 合理管理定时器与导航可避免白屏、跳转错乱等问题。

全局共享 NavPathStack

  1. 非 Navigation 子页如何实现页面跳转?

    • 全局共享 NavPathStack
    • AppStorageV2:可以提供状态变量在应用级全局共享的能力
  2. 如何使用 AppStorageV2?
    AppStorageV2.connect( NavPathStack, // 类型 (Type) 'navStack', // key () => new NavPathStack() // 初始化值 (Factory) )!

1. 为什么要“全局共享 NavPathStack”?

在 ArkUI/Stage 模式中,Navigation 组件自身会维护一棵页面栈。但当你在 非 Navigation 子组件(例如 Dialog、Service 侧滑页、Overlay 层)里需要跳转其它界面时,就无法直接拿到父级导航器。
NavPathStack 通过 AppStorageV2 注册为 全局单例 后,任何位置都可安全地:

AppStorageV2.get<NavPathStack>('navStack')?.push('DetailPage');

优势

  • 解耦:子组件不再硬依赖父级 Navigation
  • 生命周期可控:全局唯一栈实例随 app 存活,避免多处重复创建。

2. AppStorageV2.connect 的 3 个参数

序号作用典型写法
1. 类型 (Type)用于类型推断,IDE 自动补全NavPathStack
2. key全局唯一字符串标识'navStack'
3. 初始化函数首次取值时执行,返回默认实例() => new NavPathStack()

3. 常见用法示例

// ① 全局初始化(例如在 @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. 实战注意事项

  1. 统一管理路径常量
    推荐定义 enum RouteNames,避免硬编码字符串导致的跳转失败。
  2. 线程安全
    UI 线程以外访问时,务必派发到主线程,保证栈操作与渲染同步。
  3. 栈深度监控
    若频繁跳转,考虑在 push() 前检测 depth,超阈值时清理无用页面。
  4. 模块化项目
    每个 Feature 可以把自身路由注册到一个 RouteRegistry,再由公共 navStack 调度,方便动态化加载。

5. 何时不适合用全局 NavPathStack?

  • 强耦合导航逻辑:若某模块需要独立返回栈(如登录流程),局部 Navigation 仍是更干净的做法。
  • 多窗口 / 多任务模式:不同窗口应持有各自的 NavPathStack,避免状态混淆。

总结
NavPathStack 暴露为应用级状态,是在非 Navigation 子页发起路由跳转的简单又可靠方案;
利用 AppStorageV2.connect() 创建单例后,任何组件都可随取随用,同时保持类型安全与生命周期可控。

课程源码

补全了除AI生成的代码的全部源码: 黑马云音乐源码