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

基础入门

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

  • 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
}

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

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

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

    • 语法:对象名.属性名

拓展理解

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

函数

typescript 复制代码
function calc(r: number) {
  return 2 * 3.14 * r
}

let c1: number = calc(5)

  1. 函数语法规则

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

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

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

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

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

    • 非必须

拓展说明

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

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

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

  • 无参数/无返回值

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

    typescript 复制代码
    function printMsg(msg: string) {
      console.log(msg)
    }
    printMsg("Hi")

箭头函数

  1. 箭头函数的写法是?

    typescript 复制代码
    () => {}

代码示例:

typescript 复制代码
let sum = (num1: number, num2: number) => {
  return num1 + num2
}

拓展说明

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

  • 基本语法:

    typescript 复制代码
    (参数) => { 代码块 }
  • 没有参数时写作:() => {}

    有一个参数时可以省略括号:x => {}

    只有一行返回值时可以省略 {}return

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

组件语法

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

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

    • 容器组件:组件名{}
    • 内容组件:组件名()
      例子(右上代码框):
    ts 复制代码
    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 框架里,组件可以通过"点语法"链式设置多个属性,如:

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

  • 属性调用格式

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

图片资源的使用

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

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

    • 资源目录:

      bash 复制代码
      resources/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 })

    例:topbottomleftright 可分别设置。


拓展理解

  • 内边距(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 框架中,"可滚动组件"通常指支持滚动操作的容器,比如 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. 扩充组件安全区代码

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

拓展说明:

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

循环渲染

总结

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

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

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

    ts 复制代码
    ForEach(数组, (item: 类型, index: number) => {
        组件
    })

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

1. 循环渲染的作用

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

2. 鸿蒙中的 ForEach 语法解析

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

  • 语法如下:

    ts 复制代码
    ForEach(数据源, (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.自定义构建函数名(参数) 来调用这个构建函数,实现多次渲染、复用。

    typescript 复制代码
    this.自定义构建函数名(数据列表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. replacePathByNamepushPathByName 细节对比

特性 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]、自定义边缘

示例

ts 复制代码
Stack({ alignContent: Alignment.BottomCenter }) { ... }

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


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

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

5. 常见坑及建议

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

总结

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

    • 全局共享 NavPathStack
    • AppStorageV2:可以提供状态变量在应用级全局共享的能力
  2. 如何使用 AppStorageV2?

    AppStorageV2.connect( NavPathStack, // 类型 (Type) 'navStack', // key () => new NavPathStack() // 初始化值 (Factory) )!

在 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. 实战注意事项

  1. 统一管理路径常量
    推荐定义 enum RouteNames,避免硬编码字符串导致的跳转失败。
  2. 线程安全
    UI 线程以外访问时,务必派发到主线程,保证栈操作与渲染同步。
  3. 栈深度监控
    若频繁跳转,考虑在 push() 前检测 depth,超阈值时清理无用页面。
  4. 模块化项目
    每个 Feature 可以把自身路由注册到一个 RouteRegistry,再由公共 navStack 调度,方便动态化加载。
  • 强耦合导航逻辑 :若某模块需要独立返回栈(如登录流程),局部 Navigation 仍是更干净的做法。
  • 多窗口 / 多任务模式:不同窗口应持有各自的 NavPathStack,避免状态混淆。

总结

NavPathStack 暴露为应用级状态,是在非 Navigation 子页发起路由跳转的简单又可靠方案;

利用 AppStorageV2.connect() 创建单例后,任何组件都可随取随用,同时保持类型安全与生命周期可控。

课程源码

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

相关推荐
睡觉z1 小时前
Haproxy搭建web群集
前端
codingandsleeping2 小时前
重读《你不知道的JavaScript》(上)- this
前端·javascript
孩子 你要相信光3 小时前
前端如何通过 Blob 下载 Excel 文件
前端·javascript
IT猫咪酱3 小时前
【前端】yarn install error
前端
喜欢打篮球的普通人3 小时前
Flang:LLVM Fortran 前端简介
前端
喵喵侠w3 小时前
腾讯地图Web版解决热力图被轮廓覆盖的问题
前端·javascript
qq_2786672865 小时前
ros中相机话题在web页面上的显示,尝试js解析sensor_msgs/Image数据
前端·javascript·ros
烛阴5 小时前
JavaScript并发控制:从Promise到队列系统
前端·javascript
zhangxingchao5 小时前
Flutter的Widget世界
前端