操作ArkTS页面跳转及路由相关心得
本文为JS老狗原创。
当前端不得不关注的点:路由,今天聊一聊鸿蒙相关的一点心得。
总体上套路不意外,基本就是(尤其是Web)前端那些事:维护路由表、跳转带参数、历史堆栈操作,等等。
历史原因,ArkTS提供了两套方案:router和Navigation。我厂进入比较早,还是采用的router方案;Navigation的方案只是个人大致研究了一下。下面分别聊一聊。
使用@ohos.router
通过路由地址跳转
当我们以下图的路径创建页面时,开发工具会自动记录一个页面路由:


文件路径:src/main/resources/base/profile/main_pages.json

在同一module中,我们可以使用@ohos.router库快速实现页面跳转:
import router from '@ohos.router';@Entry
@Component
struct Index {build() {Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Button('Page1').onClick(() => {router.pushUrl({ url: 'pages/Page1' })})}.width('100%').height('100%')}
}
效果如下:

这个操作过程,跟小程序的创建页面和自动记录路由的过程非常类似,跳转过程跟各路router也差不多。
当然我们也可手动创建文件,以及手工维护这个路由表。
通过路由命名跳转
我们可以在@Entry装饰器上,对页面进行路由命名:
@Entry({ routeName: 'Page2' })
@Component
struct Page2 {@State message: string = 'Page2';build() {RelativeContainer() {Text(this.message).id('Page2HelloWorld').fontSize(50).fontWeight(FontWeight.Bold).alignRules({center: { anchor: '__container__', align: VerticalAlign.Center },middle: { anchor: '__container__', align: HorizontalAlign.Center }})}.height('100%').width('100%')}
}
然后在索引页面上,import这个页面,通知注册路由名称:
import router from '@ohos.router';
import './Page2'
// ...
这里只是为了注册routeName,需要代码层import一个页面,并不是很优雅。
另外还有一种import('./Page2.ets')的方式,意思差不多,只是这里算动态引用。我们在某些windows模拟器上发现只能使用这种动态引用,复现不稳定,如有问题可试试这种方式。
新增一个按钮,使用router.pushNamedRoute向Page2跳转:
Button('Page2').onClick(() => {router.pushNamedRoute({ name: 'Page2' })
})
看下效果:

由于路由表是维护在module内的,所以当时项目使用多module时,使用routeName跳转会比较方便。唯一的缺点就是需要额外import页面。
参数传递
跳转时代入params,用于传递参数:
router.pushUrl({ url: 'pages/Page1', params: { productId: '123' } })
在目标页,使用router.getParams()获取参数:
import router from '@ohos.router';@Entry
@Component
struct Page1 {@State message: string = 'Page1';@State productId: string = ''onPageShow(): void {const params = (router.getParams() || {}) as Record<string, Object>this.productId = `${params.productId || ''}`}build() {// ...}
}

请注意router.getParams()又可能返回null,取值请注意降级。
另外,上面例子是在onPageShow阶段获取,如果是从其他页面back回来的,这种方式有可能会导致页面参数取值错误。
使用NavPathStack+Navigation
其中NavPathStack是路由堆栈,Navigation是UI组件,可以快捷实现页头、底部tabBar等功能能。两者必须结合使用。
构建索引页
我们把Index页面重构一下:
import router from '@ohos.router';
import './Page2'@Entry
@Component
struct Index {routeStack = new NavPathStack()build() {Navigation(this.routeStack) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Button('Page1').onClick(() => {router.pushUrl({ url: 'pages/Page1' })}).margin({ bottom: 10 })Button('Page2').onClick(() => {router.pushNamedRoute({ name: 'Page2' })}).margin({ bottom: 10 })}.width('100%').height('100%')}}
}
由于我们未对Navigation组件做任何配置,所以现在页面看不出变化。
维护路由表
这个过程可以简单分3步,请依次完成。首先打开冰箱……
1、创建Page3,仅用@Component装饰;使用Page3构建一个@Builder声明为Page3Builder并导出:
@Builder
export function Page3Builder() {Page3()
}@Component
struct Page3 {@State message: string = 'Page3';build() {RelativeContainer() {Text(this.message)//...}.height('100%').width('100%')}
}
2、在目录src/main/resources/base/profile中,创建文件route_map.json,指向上面的Page3,命名为page3。
这里的命名建议不要区分大小写,比如驼峰什么的就算了,全小写+数字+下划线不容易出错。
{"routerMap": [{"name": "page3","pageSourceFile": "src/main/ets/pages/Page3.ets","buildFunction": "Page3Builder"}]
}
3、将路由表在module.json5中注册:
{"module": {// ..."routerMap": "$profile:route_map"// ...}
}
4、没想到吧,其实这一步最重要了:使用NavDestination包裹Page3,否则跳过去也是白屏。
@Builder
export function Page3Builder() {Page3()
}@Component
struct Page3 {@State message: string = 'Page3';build() {NavDestination() {RelativeContainer() {Text(this.message).id('Page3HelloWorld').fontSize(50).fontWeight(FontWeight.Bold).alignRules({center: { anchor: '__container__', align: VerticalAlign.Center },middle: { anchor: '__container__', align: HorizontalAlign.Center }})}.height('100%').width('100%')}}
}
5、对其实还有一步:在索引页中发起跳转:
Button('Page3').onClick(() => {this.routeStack.pushPath({ name: 'page3' })
}).margin({ bottom: 10 })

注意这里的跳转名应当严格一致。
看下效果:

当然你一定发现了,Page3的左上角有个返回按钮,这就是NavDestination的效果之一。Navigation相关的路由跳转,现在是官方的推荐做法。
参数传递

哎,令人无奈。两个槽点:
- 哪里冒出来的
unknown类型; - router的参数名是
params,怎么这里又成了param?
改造Page3
@Builder
export function Page3Builder(name: string, param: Object) {Page3({ param })
}@Component
struct Page3 {@State message: string = 'Page3';@State product: string = ''param: Object = {} as Record<string, Object>build() {NavDestination() {RelativeContainer() {Text(`${this.message} - ${Reflect.get(this.param, 'product') || ''}`)//...}.height('100%').width('100%')}}
}
请注意Page3Builder的参数传递,以及在Page3构建时传入的参数。
另外也可在NavDestination.onReady周期获取上下文,从上下文中拿到参数:
build() {NavDestination() {// 。。。}.onReady(context => {this.product = Reflect.get(context.pathInfo.param, 'product')})
}
别问Reflect.get是啥,用就是了。
Navigation的UI配置
Navigation的UI配置非常丰富,可以看出这个组件在开发时对各路路由UI都做了充分的调研,用起来让人觉得简单得有点不敢相信。
构建页头
最简单的,给页头起个名字,并设置页头大小。
@Entry
@Component
struct Index {routeStack = new NavPathStack()build() {Navigation(this.routeStack) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {// ...}.width('100%').height('100%').backgroundColor('#fff')}.title('首页').titleMode(NavigationTitleMode.Mini).backgroundColor('#f1f1f1')}
}
看下效果:

这里titleMode的枚举值有:
NavigationTitleMode.Mini

- NavigationTitleMode.Full / NavigationTitleMode.Free

自定义UI的页头
在页面中写个@Builder:
@Builder
NavBar() {Flex({direction: FlexDirection.Column,justifyContent: FlexAlign.Center,alignItems: ItemAlign.Center,}) {Text('首页').fontSize(16)}.width('100%').height('100%').position({ x: 0 }).zIndex(-1)
}
在build()中输入这个自定义页头:
build() {Navigation(this.routeStack) {Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {Button('Page1').onClick(() => {router.pushUrl({ url: 'pages/Page1' })}).margin({ bottom: 10 })Button('Page2').onClick(() => {router.pushNamedRoute({ name: 'Page2' })}).margin({ bottom: 10 })Button('Page3').onClick(() => {this.routeStack.pushPath({ name: 'page3' })}).margin({ bottom: 10 })}.width('100%').height('100%').backgroundColor('#fff')}.title(this.NavBar) // <<<<------- 看这里.titleMode(NavigationTitleMode.Mini).backgroundColor('#f1f1f1')
}

请注意NavBar中用了一个zIndex(-1),这样就不会遮挡返回按钮了。
底部TabBar配置
先看下效果:

toolbarConfiguration
build() {Navigation(this.routeStack) {// ...}.title(this.NavBar).titleMode(NavigationTitleMode.Mini).backgroundColor('#f1f1f1').toolbarConfiguration([{icon: 'https://res.suning.cn/project/cmsWeb/suning/homepage/v8/css/images/tool-logo.png',value: '首页',action: () => {router.pushUrl({ url: 'pages/Page1' })}},{icon: 'https://image.suning.cn/uimg/cms/img/157105762930982264.png',value: '购物车',action: () => {this.routeStack.pushPath({ name: 'page3' })}},{icon: 'https://image.suning.cn/uimg/cms/img/157105768303272975.png',value: '我的',action: () => {router.pushNamedRoute({ name: 'Page2' })}}])
}
简简单单,配置icon/value/action,即出成品。
写在最后
这个阶段对路由的研究,大致就是如此。感觉像Navigation在UI方面的表现,应该还有不少可以深挖的地方。
前面也有大佬们提过,ArkTS跟Flutter像,以及模式、架构跟mvvm也有相近之处,到了路由这部分,其实跟rn也有些相似了。
作为后来者,相信ArkTS能够吸取众家之长,成为集大成者。
关于OpenTiny
欢迎加入 OpenTiny 开源社区。添加微信小助手:opentiny-official 一起参与交流前端技术~
OpenTiny 官网:https://opentiny.design/
TinyVue 源码:https://github.com/opentiny/tiny-vue
TinyEngine 源码: https://github.com/opentiny/tiny-engine
OpenTiny HUICharts 源码:https://github.com/opentiny/tiny-charts
欢迎进入代码仓库 Star🌟TinyEngine、TinyVue、TinyNG、TinyCLI~ 如果你也想要共建,可以进入代码仓库,找到 good first issue标签,一起参与开源贡献~
(温馨提示:OpenTiny CCF开源创新大赛也在持续报名中,欢迎大家一起报名参赛,赢取10W奖金)
相关文章:
操作ArkTS页面跳转及路由相关心得
本文为JS老狗原创。 当前端不得不关注的点:路由,今天聊一聊鸿蒙相关的一点心得。 总体上套路不意外,基本就是(尤其是Web)前端那些事:维护路由表、跳转带参数、历史堆栈操作,等等。 历史原因&…...
Vue2-低版本编译兼容-基础语法-data-methods-双向数据绑定v-model
文章目录 1.安装编译命令2.低版本兼容3.vue2响应式数据3.1.data定义3.2.双向数据绑定v-model3.3.单向数据绑定v-bind4.方法methods5.子组件向父组件传值6.父组件向子组件传值1.安装编译命令 命令行工具 vue create zhiliaoplugins8824barcodebatch cd zhiliaoplugins8824barc…...
提取“c语言的函数定义“脚本
------------------------------------------------------------ author: hjjdebug date: 2024年 08月 11日 星期日 16:35:31 CST description: 提取c语言的函数定义脚本 ------------------------------------------------------------ c 文件中包含很多函数定义, 我想在每…...
pytorch学习(十二):对现有的模型进行修改
以VGG16为例: VGG((features): Sequential((0): Conv2d(3, 64, kernel_size(3, 3), stride(1, 1), padding(1, 1))(1): ReLU(inplaceTrue)(2): Conv2d(64, 64, kernel_size(3, 3), stride(1, 1), padding(1, 1))(3): ReLU(inplaceTrue)(4): MaxPool2d(kernel_size2…...
服务器虚拟内存是什么?虚拟内存怎么设置?
服务器虚拟内存是计算机系统内存管理的一种重要技术,它允许应用程序认为它们拥有连续且完整的内存地址空间,而实际上这些内存空间是由多个物理内存碎片和外部磁盘存储器上的空间共同组成的。当物理内存(RAM)不足时,系统…...
深度学习入门指南(1) - 从chatgpt入手
2012年,加拿大多伦多大学的Hinton教授带领他的两个学生Alex和Ilya一起用AlexNet撞开了深度学习的大门,从此人类走入了深度学习时代。 2015年,这个第二作者80后Ilya Sutskever参与创建了openai公司。现在Ilya是openai的首席科学家,…...
Python学习笔记(六)
""" 演示对序列进行切片操作 """ # 切片;从一个序列中,取出一个子序列 # 语法[起始下标:结束下标:步长] # 这三个都不写也行,视为从头到尾步长为1 # 起始下标不写,视作从头开…...
大数据安全规划总体方案(45页PPT)
方案介绍: 大数据安全规划总体方案的制定,旨在应对当前大数据环境中存在的各类安全风险,包括但不限于数据泄露、数据篡改、非法访问等。通过构建完善的安全防护体系,保障大数据在采集、存储、处理、传输、共享等全生命周期中的安…...
第20周:Pytorch文本分类入门
目录 前言 一、前期准备 1.1 环境安装导入包 1.2 加载数据 1.3 构建词典 1.4 生成数据批次和迭代器 二、准备模型 2.1 定义模型 2.2 定义示例 2.3 定义训练函数与评估函数 三、训练模型 3.1 拆分数据集并运行模型 3.2 使用测试数据集评估模型 总结 前言 …...
记一次 SpringBoot2.x 配置 Fastjson请求报 internal server 500
1.遇到的问题 报错springboot从2.1.16升级到2.5.15,之后就报500内部错误,后面调用都是正常的,就考虑转换有错。 接口返回错误: 2.解决办法 因为我用了fastjson,需要转换下,目前可能理解就是springboot-we…...
OSPF笔记
OSPF:开放式最短路径优先协议 使用范围:IGP 协议算法特点:链路状态型路由协议,SPF算法 协议是否传递网络掩码:传递网络掩码 协议封装:基于ip协议封装,协议号为89 一,ospf特点 1…...
IOC容器初始化流程
IOC容器初始化流程 一、概要1.准备上下文prepareRefresh()2. 获取beanFactory:obtainFreshBeanFactory()3. 准备beanFactory:prepareBeanFactory(beanFactory)4. 后置处理:postProcessBeanFactory()5. 调用bean工厂后置处理器:invokeBeanFactoryPostProcessors()6. 注册bea…...
第二季度云计算市场份额榜单:微软下滑,谷歌上升,AWS仍保持领先
2024 年第二季度,随着企业云支出达到 790 亿美元的新高,三大云计算巨头微软、谷歌云和 AWS的全球云市场份额发生了变化。 根据新的市场数据,以下是 2024 年第二季度全球云市场份额结果和六大世界领先者,其中包括 AWS、阿里巴巴、…...
三点确定圆心算法推导
已知a,b,c三点求过这三点的圆心坐标 a ( x 1 , y 1 ) a(x_1, y_1) a(x1,y1) 、 b ( x 2 , y 2 ) b(x_2, y_2) b(x2,y2) 、 c ( x 3 , y 3 ) c(x_3, y_3) c(x3,y3) 确认三点是否共线 叉积计算方式 v → ( X 1 , Y 1 ) u → ( X 2 , Y 2 ) X 1 Y 2 − X 2 Y 1 \…...
神经网络 (NN) TensorFlow Playground在线应用程序
神经网络 (NN) 历史上最重要的发现之一是神经网络 (NN) 的强大功能。 在神经网络中,称为神经元的许多数据层被添加在一起或相互堆叠以计算新的数据级别。 常用的简称: DNN 深度神经网络CNN 卷积神经网络RNN 循环神经网络 神经元 科学家一致认为&am…...
腾讯课堂 离线m3u8.sqlite转成视频
为了广大腾讯课堂用户对于购买的课程不能正常离线播放,构成知识付费损失,故出此文档。 重点:完全免费!!!完全免费!!!完全免费!!! 怎么…...
Linux多路转接
文章目录 IO模型多路转接select 和 pollepoll IO模型 在还在学习语言的阶段,C里使用cin,或者是C使用scanf的时候,总是要等着我们输入数据才执行,这种IO是阻塞IO。下面是比较正式的说法。 阻塞IO: 在内核将数据准备好之前…...
IDEA导入Maven项目的流程配置以常见问题解决
1. 前言 本文主要围绕着在IDEA中导入新Maven项目后的配置及常见问题解决来展开说说。相关的部分软件如下: IntelliJ IDEA 2021.1JDK 1.8Window 2. 导入Maven项目及配置 2.1 导入Maven项目 下面介绍了直接打开本地项目和导入git上的项目两种导入Maven方式。 1…...
【数据分析---- Pandas进阶指南:核心计算方法、缺失值处理及数据类型管理】
前言: 💞💞大家好,我是书生♡,本阶段和大家一起分享和探索数据分析,本篇文章主要讲述了:Pandas进阶指南:核心计算方法、缺失值处理及数据类型管理等等。欢迎大家一起探索讨论&#x…...
2024世界机器人大会将于8月21日至25日在京举行
2024年的世界机器人大会预定于8月21日至25日,在北京经济技术开发区的北人亦创国际会展中心隆重举办。 本届大会以“共育新质生产力 共享智能新未来”为核心主题,将汇聚来自全球超过300位的机器人行业专家、国际组织代表、杰出科学家以及企业家࿰…...
REFramework终极指南:让RE引擎游戏体验焕然一新的完整解决方案
REFramework终极指南:让RE引擎游戏体验焕然一新的完整解决方案 【免费下载链接】REFramework Mod loader, scripting platform, and VR support for all RE Engine games 项目地址: https://gitcode.com/GitHub_Trending/re/REFramework REFramework是专为RE…...
04月06日AI每日参考:Gemma4颠覆参数论 阿里OpenAI频放新动作
今日概览今日AI圈迎来技术与商业双重爆发,谷歌Gemma 4以小参数模型打破行业"参数迷信",为端侧AI普及按下加速键。阿里、OpenAI等头部玩家同步放出新动作,国产大模型与芯片的组合也传来突破性消息,全行业的技术路线和市场…...
零基础入门:Qwen3-ASR-1.7B语音识别Docker部署全流程
零基础入门:Qwen3-ASR-1.7B语音识别Docker部署全流程 1. 为什么选择Docker部署语音识别服务 想象一下,你刚学会使用Qwen3-ASR-1.7B这个强大的语音识别模型,在本地电脑上测试效果非常棒。但当你想把它部署到服务器上时,突然发现各…...
【MATLAB源码-第320期】基于matlab的混沌序列图像加密解密系统仿真,测试加解密速度、资源占用、模糊攻击测试、密钥空间和敏感性分析。
操作环境:MATLAB 2024a1、算法描述基于混沌序列的图像加密 与解密系统 随着数字信息技术的迅速发展,图像作为信息载体的使用越来越广泛。然而,图像数据在传输和存储过程中容易受到窃取、篡改或破坏,因此确保图像数据的安全性显得尤…...
使用MobaXterm高效管理远程PyTorch训练:图形化SFTP与中文设置
使用MobaXterm高效管理远程PyTorch训练:图形化SFTP与中文设置 1. 为什么选择MobaXterm进行AI开发 在深度学习项目开发中,我们经常需要在远程服务器上运行PyTorch训练任务。传统的SSH工具虽然能完成基本操作,但在文件传输、可视化管理和多任…...
小白也能用!M2FP多人人体解析服务一键部署教程
小白也能用!M2FP多人人体解析服务一键部署教程 1. 什么是M2FP多人人体解析服务? M2FP(Mask2Former-Parsing)是目前业界领先的语义分割算法,专注于多人人体解析任务。它能精准识别图像中多个人物的不同身体部位&#…...
OpenClaw数据可视化:千问3.5-9B自动生成分析图表
OpenClaw数据可视化:千问3.5-9B自动生成分析图表 1. 为什么需要AI驱动的数据可视化? 上周我面对一个典型的数据分析困境:手头有3份Excel表格,分别是销售数据、用户行为日志和库存记录。老板要求第二天早晨提交可视化报告&#x…...
轻松掌握gallery多渠道打包:为不同应用商店构建专属本地AI平台版本
轻松掌握gallery多渠道打包:为不同应用商店构建专属本地AI平台版本 【免费下载链接】gallery A gallery that showcases on-device ML/GenAI use cases and allows people to try and use models locally. 项目地址: https://gitcode.com/GitHub_Trending/gallery…...
嵌入式开发代码比对工具实战指南
1. 单片机开发中的代码版本管理痛点 在嵌入式开发领域,代码版本管理是每个工程师的必修课。我经历过无数次深夜调试时,突然发现某个功能在上一版还能正常工作,最新修改后却出现了异常。这时候,快速定位两个版本间的代码差异就成了…...
JAVA无人共享无人机赁柜预约小程序源码代码
JAVA无人共享无人机租赁柜预约小程序源码实现方案采用Uniapp框架开发无人共享无人机租赁柜预约小程序,需整合后端Java服务和前端跨平台技术。以下是核心实现方案:技术栈选择前端:Uniapp Vue.js uView UI后端:Spring Boot MyBat…...
