操作ArkTS页面跳转及路由相关心得

server/2024/9/23 5:21:25/
webkit-tap-highlight-color: rgba(0, 0, 0, 0);">

本文为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_503">关于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奖金)


http://www.ppmy.cn/server/98324.html

相关文章

ceph

ceph是一个开源的&#xff0c;用c语言编写的分布式的存储系统。存储文件数据。 /dev/sdb fdisk /dev/sdb gdisk /dev/sdb lvm 逻辑卷 可以扩容 raid 磁盘 高可用 基于物理意义上的单机的存储系统。 分布式由多台物理磁盘组成一个集群&#xff0c;在这个基础之上实现高可…

达梦数据库(九) -------- JAVA 的连接配置方式

连接单机数据库配置如下&#xff1a; 集群配置连接如下&#xff1a; 在 dm_svc.conf 文件中配置服务名&#xff0c;通过服务名连接集群可实现故障自动重连。 Window 环境 Windows 平台 dm_svc.conf 文件位 %SystemRoot%\system32 目录下&#xff1a; Linux 环境 Linux 平台…

渠道刷量怎么办?Xinstall来帮你一键识破!

在App推广的道路上&#xff0c;数据是我们最得力的助手&#xff0c;也是我们最头疼的难题。每日下载量、安装量、注册量……这些看似简单的数字&#xff0c;背后却隐藏着无数的故事。哪个渠道在默默发力&#xff1f;哪个渠道又在浑水摸鱼&#xff1f;这一切&#xff0c;都需要我…

【C语言】UDP通信

udp使用的是数据报传输。可以一对一&#xff0c;一对多进行传输&#xff0c;用于快速&#xff0c;实时性高的场景 服务器端&#xff1a; 使用步骤&#xff1a; 1.创建socket 2.bind绑定可接收的客户端 3.while{ recv接收数据 send发送数据 } #include <stdio.h> #inclu…

c++_狼人杀升级版

#include <bits/stdc.h> #include <windows.h> #include <conio.h> #include <stdlib.h> #include <stdio.h> #define random(a,b) (rand()%(b-a1)a) using namespace std;//命名空间 int a[6]{0,0,0,0,0,0}; struct node{string sf; }sfs[4]; v…

Java中的分布式日志与追踪

随着微服务架构的流行&#xff0c;分布式系统变得越来越复杂。在分布式系统中&#xff0c;日志和追踪是两个关键的工具&#xff0c;用于监控系统的健康状态、故障排除和性能优化。本文将详细探讨Java中的分布式日志与追踪&#xff0c;介绍相关的技术和工具&#xff0c;并通过代…

清韵千言-小思——一个强大的AI大语言模型接口

介绍 清韵千言-小思 是一款由我们的团队自主研发的大规模语言模型接口。该模型不仅能够处理各种自然语言任务&#xff0c;而且它的大部分能力已经超越了GPT-3.5等模型。尽管如此&#xff0c;小思也有一些特定的限制条件&#xff0c;比如不支持上下文记忆、不支持并发请求等。下…

SX_SM2002_RTC模块的烧录与调试_8

1、烧录&#xff1a; 首先git上下载项目到本地会下载所有项目&#xff0c;包括所有分支内容&#xff0c;烧录的话得在对应开发板子的分支下烧录&#xff0c;因为各分支的代码是不同的&#xff0c;得在本地切换到相应板子的分支烧录&#xff0c;切换后本地文件也会做相应改变 切…