写点什么

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

作者:OpenTiny社区
  • 2024-08-09
    中国香港
  • 本文字数:5231 字

    阅读完需:约 17 分钟

操作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@Componentstruct 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' })@Componentstruct 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@Componentstruct 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@Componentstruct 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并导出:


@Builderexport function Page3Builder() {    Page3()}
@Componentstruct 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,否则跳过去也是白屏。


@Builderexport function Page3Builder() {    Page3()}
@Componentstruct 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


@Builderexport function Page3Builder(name: string, param: Object) {    Page3({ param })}
@Componentstruct 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@Componentstruct 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


@BuilderNavBar() {    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奖金

用户头像

OpenTiny 企业级web前端开发解决方案 2023-06-06 加入

官网:opentiny.design 我们是华为云的 OpenTiny 开源社区,会定期为大家分享一些团队内部成员的技术文章或华为云社区优质博文,涉及领域主要涵盖了前端、后台的技术等。

评论

发布
暂无评论
操作ArkTS页面跳转及路由相关心得_开源_OpenTiny社区_InfoQ写作社区