当前位置: 首页 > news >正文

操作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.pushNamedRoutePage2跳转:

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奖金)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 矩阵:消除冗余
  • 逻辑数仓:助企业高效、低成本、轻量级整合全域数据
  • 【MySQL】执行DDL选择Online DDL还是PT-OSC?
  • [BSidesCF 2019]Kookie1
  • 算法笔记|Day20回溯算法II
  • Jenkins部署java项目
  • JAVA集中学习第四周学习记录(三)
  • 测试用例除了覆盖需求,还需要通过什么方式保证测试?
  • 深入理解和应用RabbitMQ的Work Queues模型
  • 00 cadence学习笔记目录
  • python-约瑟夫环(赛氪OJ)
  • Python 爬虫项目实战一:抖音视频下载与网易云音乐下载
  • 什么是DNS缓存?DNS缓存有哪些作用和危害?
  • 六大设计原则和23种设计模式
  • Linux-vim编辑器以及权限-04
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • 【跃迁之路】【519天】程序员高效学习方法论探索系列(实验阶段276-2018.07.09)...
  • 30秒的PHP代码片段(1)数组 - Array
  • AWS实战 - 利用IAM对S3做访问控制
  • ComponentOne 2017 V2版本正式发布
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • js操作时间(持续更新)
  • MaxCompute访问TableStore(OTS) 数据
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • Web设计流程优化:网页效果图设计新思路
  • 首页查询功能的一次实现过程
  • 数据仓库的几种建模方法
  • hi-nginx-1.3.4编译安装
  • 关于Android全面屏虚拟导航栏的适配总结
  • ​力扣解法汇总1802. 有界数组中指定下标处的最大值
  • !!java web学习笔记(一到五)
  • # Java NIO(一)FileChannel
  • #NOIP 2014# day.2 T2 寻找道路
  • #我与Java虚拟机的故事#连载07:我放弃了对JVM的进一步学习
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • ( 10 )MySQL中的外键
  • (k8s中)docker netty OOM问题记录
  • (LLM) 很笨
  • (LNMP) How To Install Linux, nginx, MySQL, PHP
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (终章)[图像识别]13.OpenCV案例 自定义训练集分类器物体检测
  • (转)视频码率,帧率和分辨率的联系与区别
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • (自用)交互协议设计——protobuf序列化
  • *ST京蓝入股力合节能 着力绿色智慧城市服务
  • .NET Core中的时区转换问题
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • .Net(C#)常用转换byte转uint32、byte转float等
  • @angular/cli项目构建--Dynamic.Form
  • [AutoSar]BSW_Memory_Stack_004 创建一个简单NV block并调试
  • [BPU部署教程] 教你搞定YOLOV5部署 (版本: 6.2)
  • [C++]Leetcode17电话号码的字母组合