操作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位的机器人行业专家、国际组织代表、杰出科学家以及企业家࿰…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
ubuntu22.04 安装docker 和docker-compose
首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...
