【HarmonyOS开发】Navigation使用
简介
Navigation是路由容器组件,包括单栏(Stack)、分栏(Split)和自适应(Auto)三种显示模式。适用于模块内和跨模块的路由切换。
在页面跳转时,应该使用页面路由router,在页面内的页面跳转时,建议使用Navigation达到更好的转场动效场景。
UI框架

显示模式
通过mode属性来定义
Navigation() {...
}
.mode(NavigationMode.Auto)
自适应(Auto)模式
组件默认的模式,当页面宽度大于等于一定阈值( API version 9及以前:520vp,API version 10及以后:600vp )时,Navigation组件采用分栏模式,反之采用单栏模式。
单栏(Stack)模式

分栏(Split)模式

标题栏模式
通过titleMode属性设置标题栏模式,分别有Mini模式和Full模式
- Mini模式

- Full模式

菜单栏
通过menus属性进行设置。支持Array和CustomBuilder两种类型。
注意:使用Array时,竖屏最多支持3个图标,横屏最多支持5个图标
@Entry
@Component
struct Index {ToolTmp: NavigationMenuItem = {value: "",icon: "resources/base/media/startIcon.png",action: () => {}}build() {Column() {Navigation() {}.title("主标题").titleMode(NavigationTitleMode.Full).menus([this.ToolTmp,this.ToolTmp,this.ToolTmp])}.width("100%").height("100%").backgroundColor('#F1F3F5')}
}
工具栏
工具栏位于Navigation组件的底部,通过toolbarConfiguration属性进行设置。
@Entry
@Component
struct Index {ToolTmp: NavigationMenuItem = {value: "",icon: "resources/base/media/startIcon.png",action: () => {}}Toolbar: ToolbarItem = {value: "test",icon: $r('app.media.app_icon'),action: () => {}}build() {Column() {Navigation() {}.title("主标题").titleMode(NavigationTitleMode.Full).menus([this.ToolTmp,this.ToolTmp,this.ToolTmp]).toolbarConfiguration([this.Toolbar,this.Toolbar,this.Toolbar])}.width("100%").height("100%").backgroundColor('#F1F3F5')}
}
路由操作
Navigation路由相关的操作都是基于页面栈NavPathStack对象。主要涉及页面跳转、页面返回、页面替换、页面删除、参数获取、路由拦截等功能。
定义一个NavPathStack对象:pageStack: NavPathStack = new NavPathStack()

页面跳转
- 普通跳转,通过页面的name去跳转
this.pageStack.pushPathByName("PageOne", "PageOne Param")
- 带返回回调的跳转,跳转时添加onPop回调,能在页面出栈时获取返回信息,并进行处理。
this.pageStack.pushPathByName('PageOne', "PageOne Param", (popInfo) => {
console.log('Pop page name is: ' + popInfo.info.name + ', result: ' + JSON.stringify(popInfo.result))
});
- 带错误码的跳转,跳转结束会触发异步回调,返回错误码信息。
this.pageStack.pushDestinationByName('PageOne', "PageOne Param")
.catch((error: BusinessError) => {console.error(`Push destination failed, error code = ${error.code}, error.message = ${error.message}.`);
}).then(() => {
console.error('Push destination succeed.');
});
页面返回
// 返回到上一页
this.pageStack.pop()
// 返回到上一个PageOne页面
this.pageStack.popToName("PageOne")
// 返回到索引为1的页面
this.pageStack.popToIndex(1)
// 返回到根首页(清除栈中所有页面)
this.pageStack.clear()
页面替换
this.pageStack.replacePathByName("PageOne", "PageOne Param")
页面删除
// 删除栈中name为PageOne的所有页面
this.pageStack.removeByName("PageOne")
// 删除指定索引的页面
this.pageStack.removeByIndexes([1,3,5])
页面参数获取
// 获取栈中所有页面name集合
this.pageStack.getAllPathName()
// 获取索引为1的页面参数
this.pageStack.getParamByIndex(1)
// 获取PageOne页面的参数
this.pageStack.getParamByName("PageOne")
// 获取PageOne页面的索引集合
this.pageStack.getIndexByName("PageOne")
页面转场
Navigation默认提供了页面切换的转场动画,通过页面栈操作时,会触发不同的转场效果(Dialog类型的页面默认无转场动画),Navigation也提供了关闭系统转场、自定义转场以及共享元素转场的能力。
关闭转场
- 全局关闭
pageStack: NavPathStack = new NavPathStack()aboutToAppear(): void {this.pageStack.disableAnimation(true)
}
- 单次关闭
pageStack: NavPathStack = new NavPathStack()this.pageStack.pushPath({ name: "PageOne" }, false)
this.pageStack.pop(false)
子页面显示类型
- 标准类型(NavDestinationMode.STANDARD),生命周期跟随其在NavPathStack页面栈中的位置变化而改变。
- 弹窗类型(NavDestinationMode.DIALOG),显示和消失时不会影响下层标准类型的NavDestination的显示和生命周期,两者可以同时显示。
子页面生命周期(NavDestination)

- aboutToAppear:在创建自定义组件后,执行其build()函数之前执行(NavDestination创建之前),允许在该方法中改变状态变量,更改将在后续执行build()函数中生效。
- onWillAppear:NavDestination创建后,挂载到组件树之前执行,在该方法中更改状态变量会在当前帧显示生效。
- onAppear:通用生命周期事件,NavDestination组件挂载到组件树时执行。
- onWillShow:NavDestination组件布局显示之前执行,此时页面不可见(应用切换到前台不会触发)。
- onShown:NavDestination组件布局显示之后执行,此时页面已完成布局。
- onWillHide:NavDestination组件触发隐藏之前执行(应用切换到后台不会触发)。
- onHidden:NavDestination组件触发隐藏后执行(非栈顶页面push进栈,栈顶页面pop出栈或应用切换到后台)。
- onWillDisappear:NavDestination组件即将销毁之前执行,如果有转场动画,会在动画前触发(栈顶页面pop出栈)。
- onDisappear:通用生命周期事件,NavDestination组件从组件树上卸载销毁时执行。
- aboutToDisappear:自定义组件析构销毁之前执行,不允许在该方法中改变状态变量。
使用案例
实现简单的登录界面跳转。

项目目录

Index
import { component_1 } from '../Components/component_1';
import { component_2 } from '../Components/component_2';
import { LoginParam } from '../Models/LoginParam';@Entry
@Component
struct Index {@Provide("pageNavigation") pageNav: NavPathStack = new NavPathStack();@BuilderPageMap(path: string) {if (path == "component_1") {component_1()}if (path == "component_2") {component_2()}}build() {Column() {Navigation(this.pageNav) {Button("直接跳转component_1界面(不带参数)").width("80%").margin({ bottom: 20 }).onClick(() => {this.pageNav.pushPathByName("component_1", "")})Button("直接跳转component_1界面(带参数)").width("80%").margin({ bottom: 20 }).onClick(() => {let login: LoginParam = new LoginParam("张三", "1234567");this.pageNav.pushPathByName("component_1", login)})}.title("主页").titleMode(NavigationTitleMode.Full).mode(NavigationMode.Auto).navDestination(this.PageMap)}.height('100%').width('100%')}
}
component_1
import { LoginParam } from '../Models/LoginParam';
import { JSON } from '@kit.ArkTS';@Component
export struct component_1 {@Consume("pageNavigation") pageNav: NavPathStack;@State login: LoginParam = new LoginParam("", "")build() {Column() {NavDestination() {Row() {Text("账户:").fontSize(16).margin({ left: 10, right: 10 })TextInput({ text: this.login.Name, placeholder: "请输入账户" }).layoutWeight(1).margin({ right: 10 }).onChange((value) => {this.login.Name = value})}.width("100%")Row() {Text("密码:").fontSize(16).margin({ left: 10, right: 10 })TextInput({ text: this.login.Password, placeholder: "请输入密码" }).layoutWeight(1).margin({ right: 10 }).type(InputType.Password).onChange((value) => {this.login.Password = value})}.width("100%").margin({ top: 20 })Grid() {GridItem() {Button("注册").width("100%").backgroundColor("#f1f2f3").fontColor("#007dfe").onClick(() => {this.pageNav.pushPathByName("component_2", this.login.Name, (popInfo) => {if (popInfo.result != null) {let popLogin: LoginParam = popInfo.result as LoginParam;if (popLogin == null) {return;}this.login = popLogin;}});})}.width("50%").padding({ right: 10, left: 10 })GridItem() {Button("登录").width("100%").onClick(() => {console.log(JSON.stringify(this.login))})}.width("50%").padding({ right: 10, left: 10 })}.rowsTemplate("1tf 1tf").margin({ top: 10 }).width("100%").height(60)}.title("登录").mode(NavDestinationMode.STANDARD).onWillShow(() => {let tempPara: LoginParam[] | string[] = this.pageNav.getParamByName("component_1") as LoginParam[] | string[]if (tempPara.length == 0 || tempPara[0] == "") {return;}this.login = tempPara[0] as LoginParam})}.width("100%").height("100%")}
}
component_2
import { LoginParam } from '../Models/LoginParam'
import { promptAction } from '@kit.ArkUI';@Component
export struct component_2 {@Consume("pageNavigation") pageNav: NavPathStack;@State login: LoginParam = new LoginParam("", "");@State tempPassword: string = "";build() {Column() {NavDestination() {Row() {Text("账户:").fontSize(16).margin({ left: 10, right: 10 }).width(40)TextInput({ text: this.login.Name, placeholder: "请输入账户" }).layoutWeight(1).margin({ right: 10 }).onChange((value) => {this.login.Name = value})}.width("100%")Row() {Text("密码:").fontSize(16).margin({ left: 10, right: 10 }).width(40)TextInput({ text: this.login.Password, placeholder: "请输入密码" }).layoutWeight(1).margin({ right: 10 }).type(InputType.Password).onChange((value) => {this.login.Password = value})}.width("100%").margin({ top: 20 })Row() {Text("确认密码:").fontSize(16).margin({ left: 10, right: 10 }).width(40)TextInput({ text: $$this.tempPassword, placeholder: "请再次输入密码" }).layoutWeight(1).margin({ right: 10 }).type(InputType.Password).onChange((value) => {this.tempPassword = value})}.width("100%").margin({ top: 20 })Column() {Button("注册").width("100%").onClick(() => {if (this.tempPassword != "" && this.tempPassword === this.login.Password && this.login.Name != "") {this.pageNav.pop(this.login)} else {promptAction.showDialog({title: "提示",message: "注册失败,密码不一致或账户为空",buttons: [{text: "确认",color: "#000"}]})}})}.width("100%").margin({ top: 20 }).padding({ right: 10, left: 10 })}.title("注册").mode(NavDestinationMode.STANDARD).onWillShow(() => {let names: string[] = this.pageNav.getParamByName("component_2") as string[];if (names == null || names.length === 0) {return;}this.login.Name = names[0]})}.width("100%").height("100%")}
}
LoginParam
@Observed
export class LoginParam {Name: string = "";Password: string = "";constructor(name: string, password: string) {this.Name = name;this.Password = password;}
}
相关文章:
【HarmonyOS开发】Navigation使用
简介 Navigation是路由容器组件,包括单栏(Stack)、分栏(Split)和自适应(Auto)三种显示模式。适用于模块内和跨模块的路由切换。 在页面跳转时,应该使用页面路由router,在页面内的页面跳转时,建议使用Navigation达到更好的转场动效…...
计算机网络参考模型与5G协议
目录 OSI七层参考模型OSI模型vsTCP/IP模型TCP/IP协议族的组成 OSI七层参考模型 分层功能应用层网络服务与最终用户的一个接口表示层数据的表示,安全,压缩会话层建立,管理,终止会话传输层定义传输数据的协议端口号,以及流控和差错校验网络层进行逻辑地址寻址,实现不同网路之间的…...
docker自建rustdesk-server远程桌面
rustdesk简介 RustDesk 是一款可以平替 TeamViewer 的开源软件,旨在提供安全便捷的自建方案。 RustDesk 是一款功能齐全的远程桌面应用,具有以下特性: 支持 Windows、macOS、Linux、iOS、Android、Web 等多个平台。支持 VP8 / VP9 / AV1 …...
海外抖音黑屏是网络问题还是硬件问题?
随着海外抖音(TikTok)在全球范围内的普及,越来越多的用户开始体验这一短视频社交平台。然而,不少用户在使用过程中遇到了黑屏问题,这让人不禁疑惑:这究竟是网络问题还是硬件问题? 首先…...
为了实现接口缓存,专门写了个缓存库 f-cache-memory
问题起因 起因是某次发版之后,服务器接口压力过大,当场宕机,排查之后发现有个接口在首页被调十来次(六七年的老项目了,都是泪呀),后端反馈这个接口的sql很复杂,很耗性能,…...
actual combat 35 —— es
一、windows中es执行步骤 参考:https://blog.csdn.net/qq_21197507/article/details/115076913 下es安装包下es前端gitHub代码,然后npm -i安装,npm run start 启动安装kibana 二、遇到的问题 1. 第二步安装前端代码依赖报错 npm ERR! co…...
android R ext4 image打包脚本介绍
一、Android R打包指令使用介绍 (1)mkuserimg_mke2fs #./mkuserimg_mke2fs --help usage: mkuserimg_mke2fs [-h] [--android_sparse] [--journal_size JOURNAL_SIZE][--timestamp TIMESTAMP] [--fs_config FS_CONFIG][--product_out PRODUCT_OUT][--b…...
美式键盘 QWERTY 布局的来历
注:机翻,未校对。 The QWERTY Keyboard Is Tech’s Biggest Unsolved Mystery QWERTY 键盘是科技界最大的未解之谜 It’s on your computer keyboard and your smartphone screen: QWERTY, the first six letters of the top row of the standard keybo…...
ETL数据同步之DataX,附赠一套DataX通用模板
今天跟大家分享数据同步datax的模板,小伙伴们简单直接借鉴使用。 还记得上一篇关于大数据DS调度工具的分享嘛? 主流大数据调度工具DolphinScheduler之数据ETL流程-CSDN博客 里面的核心就是采用了DATAX的数据同步原理。 一,什么是DataX D…...
[论文笔记] CT数据配比方法论——1、Motivation
我正在写这方面的论文,感兴趣的可以和我一起讨论!!!!!! Motivation 1、探测原有模型的配比: 配比 与 ppl, loss, bpw, benchmark等指标 之间的关系。 2、效果稳定的配比:配比 与 模型效果 之间的规律。 Experiments 1、主语言(什么语言作为主语言,几种主语言?…...
某4G区域终端有时驻留弱信号小区分析
这些区域其实是长时间处于连接态的电信卡4G终端更容易出现。 出现问题时都是band1 100频点下发了针对弱信号的1650频点的连接态A4测量事件配置(其阈值为-106)。而这个条件很容易满足,一旦下发就会切到band3 1650频点。 而1650频点虽然下发ban…...
【体外诊断】ARM/X86+FPGA嵌入式计算机在免疫分析设备中的应用
体外诊断 信迈提供基于Intel平台、AMD平台、NXP平台的核心板、2.5寸主板、Mini-ITX主板、4寸主板、PICO-ITX主板,以及嵌入式准系统等计算机硬件。产品支持GAHDMI等独立双显,提供丰富串口、USB、GPIO、PCIe扩展接口等I/O接口,扩展性强…...
Linux上启动和停止jar
linux 后台运行jar 在Linux系统中,要想让jar包在后台运行,可以使用nohup命令和&符号。nohup命令可以使进程在后台不受挂起信号影响的执行,而&符号则是将任务放入后台执行。 以下是一个简单的命令示例,它将启动一个jar包…...
浏览器缓存:强缓存与协商缓存实现原理有哪些?
1、强缓存:设置缓存时间的,那么在这个时间内浏览器向服务器发送请求更新数据,但是服务器会让其从缓存中获取数据。 可参考:彻底弄懂强缓存与协商缓存 - 简书 2、协商缓存每次都会向浏览器询问,那么是怎么询问的呢&…...
持续集成04--Jenkins结合Gitee创建项目
前言 在持续集成/持续部署(CI/CD)的旅途中,Jenkins与版本控制系统的紧密集成是不可或缺的一环。本篇“持续集成03--Jenkins结合Gitee创建项目”将引导如何将Jenkins与Gitee(一个流行的Git代码托管平台)相结合ÿ…...
【Node.js基础02】fs、path模块
目录 一:fs模块-读写文件 1 加载fs模块对象 2 读制定文件内容文件 3 向文件中写入内容 二:path模块-路径处理 1 问题引入 2 __dirname内置变量 使用方法 一:fs模块-读写文件 fs模块封装了与本机文件系统交互方法和属性 1 加载fs模块…...
牛客TOP101:单链表的排序
文章目录 1. 题目描述2. 解题思路3. 代码实现 1. 题目描述 2. 解题思路 按我们以往的排序算法来看,针对链表来说都是太不合适,因为很多都会出现指针前移后移,后移还好说,前移对于链表来说就太难了,而且大部分都是某一个…...
数据可视化配色新工具,颜色盘多达2500+类
好看的配色,不仅能让图表突出主要信息,更能吸引读者,之前分享过很多配色工具,例如, 👉可视化配色工具:颜色盘多达3000+类,数万种颜色! 本次再分享一个配色工具pypalettes,颜色盘多达2500+类。 安装pypalettes pip install pypalettes pypalettes使用 第1步,挑选…...
SpringAI简单使用(本地模型+自定义知识库)
Ollama 简介 Ollama是一个开源的大型语言模型服务工具,它允许用户在本地机器上构建和运行语言模型,提供了一个简单易用的API来创建、运行和管理模型,同时还提供了丰富的预构建模型库,这些模型可以轻松地应用在多种应用场景中。O…...
为什么要从C语言开始编程
在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「C语言的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!!很多小伙伴在入门编程时。都…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
优选算法第十二讲:队列 + 宽搜 优先级队列
优选算法第十二讲:队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
