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

news2024/12/25 0:34:52

本文为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奖金)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1992306.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

越秀·星汇城|大城好生活

建筑&#xff0c;是美好生活的载体。而户型则是住宅的灵魂&#xff0c;一处好的居所&#xff0c;承载理想生活盛放。 细腻的美好藏在生活各个角落&#xff0c;星汇城以24小时贯穿的细节享受&#xff0c;重新定义幸福该有的舒适。诉说生活的达观&#xff0c;臻藏岁月静好。 8:…

windows系统获取网卡信息

在抓包或者使用socket&#xff0c;或者监听端口时&#xff0c;如果使用的是pcap4j类库&#xff0c;就会用到网卡信息&#xff0c;那么怎么查看本机的网卡信息呢&#xff0c;Linux的比较方便&#xff0c;直接通过ifconfig命令就能看到&#xff0c; windows的比较麻烦一点&#x…

【名单】山东省2024年度第一批DCMM贯标试点企业名单

​各市工业和信息化局&#xff1a; 为深入贯彻全省工业经济头号工程推进会议有关部署&#xff0c;全面落实《关于加快数字经济高质量发展的意见》《2024年“促进经济巩固向好、加快绿色低碳高质量发展”政策清单&#xff08;第一批&#xff09;》等文件要求&#xff0c;充分发…

从根儿上学习spring 十 之run方法启动第四段(4)

我们接着上一节已经准备开始分析AbstractAutowireCapableBeanFactory#doCreateBean方法&#xff0c;该方法是spring真正开始创建bean实例并初始化bean的入口方法&#xff0c;属于核心逻辑&#xff0c;所以我们新开一节开始分析。 图12 图12-530到536行 这几行的主要就是创建b…

先天亏钱圣体!谢瑜、陈梦、全红婵夺冠后,我看到了最残酷的社交真相——早读(逆天打工人爬取热门微信文章解读)

我怎么寻思这是普通事故 引言Python 代码第一篇 洞见 谢瑜、陈梦、全红婵夺冠后&#xff0c;我看到了最残酷的社交真相第二篇 亏麻了结尾 没想到是辆切糕车 引言 昨天文章的数据不错呀 200 的阅读 20的收藏 10:1已经是很高的比例了 再来干货吧 以后大家要是做视频 心中看到这…

Spring Cloud微服务项目聚合Swagger文档

在微服务架构中&#xff0c;每个服务通常都有自己独立的 API 文档。为了方便管理和查看所有服务的接口文档&#xff0c;我们需要将这些文档进行聚合。Spring Cloud 与 Swagger 的结合可以帮助我们实现这一目标。本文将介绍如何在 Spring Cloud 微服务项目中聚合 Swagger 文档&a…

72 成员方法、类方法、静态方法、抽象方法

在面向对象程序设计中&#xff0c;函数和方法这两个概念是有本质区别的。方法一般指与特定实例绑定的函数&#xff0c;通过对象调用方法时&#xff0c;对象本身将被作为第一个参数自动传递过去&#xff0c;普通函数并不具备这个特点。 class Demo:passt Demo()def test(self,…

html+css网页设计公司网站模版3个页面 无js 静态页面

htmlcss网页设计公司网站模版3个页面 无js 静态页面 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源…

推送给女朋友让她自己学习打光去(Stable Diffusion进阶篇:Imposing Consistent Light)

大家好我是极客菌&#xff01;&#xff01;&#xff01; 对于学过stable diffusion的小伙伴来说&#xff0c;forge UI和Comfy UI会更加熟悉一些。在IC-Light发布后&#xff0c;Openpose editor的开发者将其制作成了一个Forge UI上的插件。 **https://github.com/huchenlei/sd-…

国内有哪些可以交易上证50etf期权的平台?

随着期权交易的普及&#xff0c;越来越多的投资者开始关注期权交易app平台。期权开通方式有券商和期权分仓平台两种&#xff0c;目前期权交易费用是7元左右一张&#xff0c;期权佣金是可以根据券商的证券范围进行调整的&#xff0c;下文为大家科普国内有哪些可以交易上证50etf期…

接口入门(企业常见使用,一分钟搞定版)

目录 1、接口的定义 定义位置 接口内容 2、接口的使用 正常实现接口 接口当做函数参数 匿名实现接口 3、OPPO便签接口具体分析 总结一下&#xff1a; 1、接口的定义 定义位置 可以写在类中&#xff0c;但注意现在接口名字是 类名.接口名 可以单独写在一个文件 接口内…

Linux系统使用Docker安装RStudio服务并实现任意浏览器远程访问

文章目录 前言1. 安装RStudio Server2. 本地访问3. Linux 安装cpolar4. 配置RStudio server公网访问地址5. 公网远程访问RStudio6. 固定RStudio公网地址 前言 RStudio Server 使你能够在 Linux 服务器上运行你所熟悉和喜爱的 RStudio IDE&#xff0c;并通过 Web 浏览器进行访问…

OpenCV图像滤波(8)getGaborKernel()函数的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数返回 Gabor 滤波器系数。 Gabor 滤波器在图像处理中非常有用&#xff0c;特别是在纹理分析、特征提取和边缘检测等领域。 函数原型 Mat c…

借助树状数组的思想实现cuda版前缀和

昨天面试快手&#xff0c;面试官出了一个cuda编程题–实现前缀和。当时没有做出来&#xff0c;一直在思考是否有类似于规约树这样的解法&#xff0c;感觉好难……面试结束后搜了一下cuda前缀和的介绍&#xff0c;发现该问题是一个经典的cuda编程问题&#xff0c;NVIDIA很早之前…

论文解读,神经网络全梯度表示《Full-Gradient Representation for Neural Network Visualization》

导语 这篇论文介绍了一种新的工具&#xff0c;称为全梯度&#xff0c;用于解释神经网络的响应。这个全梯度的概念将神经网络的响应分解为两个部分&#xff1a;输入灵敏度和每个神经元的灵敏度分量。 输入灵敏度&#xff1a;输入灵敏度指的是对于神经网络输出的影响程度。它反…

node中使用http创建web服务器

1.案例代码 // 1.导入http模块 const http require(http)// 2.创建web服务器实例 const server http.createServer()// 3.为服务器实例绑定request事件&#xff0c;监听客户的请求 server.on(request,function(req,res){console.log(欢迎来到服务器);// req.url是客户端请求…

【Material-UI】Checkbox组件:标签使用详解

文章目录 一、Checkbox 组件与标签概述1. 组件介绍2. 基本用法 二、Checkbox 标签的关键特性1. 标签与复选框的结合2. 必填项3. 禁用状态4. 带有图标的复选框5. 多行标签 三、Checkbox 标签的实际应用场景1. 表单选择项2. 设置选项3. 同意条款 四、注意事项1. 无障碍支持2. 样式…

windows环境编译ffmpeg +visual studio 2022

最近在配置ffmpeg环境&#xff0c;记录一下坑点。 系统环境 visual stdio 2022 安装c桌面开发人员版 大概8g 实际下载2g左右&#xff0c;配置齐全其余不选。 然后环境配置&#xff0c;这里我使用别人的图&#xff0c;路劲都差不多。找到VS即可 PATH配置&#xff1a; 编译 …

Spring 三级缓存解决循环依赖源码分析

什么是循环依赖&#xff1f; ServiceA依赖ServiceB&#xff0c;ServiceB依赖ServiceA。 启动Spring项目时&#xff0c;如果想实例化ServiceA&#xff0c;创建完ServiceA对象后&#xff0c;需要依赖注入ServiceB的对象&#xff0c;而ServiceB实例化时&#xff0c;需要ServiceA&…

大模型场景应用全集:持续更新中

一、应用场景 1.办公场景 智能办公&#xff1a;文案生成&#xff08;协助构建大纲优化表达内容生成&#xff09;、PPT美化&#xff08;自动排版演讲备注生成PPT&#xff09;、数据分析&#xff08;生成公式数据处理表格生成&#xff09;。 智能会议&#xff1a;会议策划&…