【HarmonyOS】ArkUI - 页面路由

一、概念

页面路由是指在应用程序中实现不同页面之间的跳转和数据传递。

案例:第一次使用某个购物应用,打开时肯定会是一个登录页,在登录成功以后,会跳转到首页,然后可能会去搜索,就会进入到搜索列表页,接着呢如果搜索到某一个感兴趣的商品A,点击,就会进入到商品A的详情页,到现在为止已经访问了好多不同的页面,并且在它们之间完成了跳转,那我之前访问过的页面都去哪里了?是不是全部被销毁了?其实并没有,我们在页面跳转之间访问过的所有页面,都会被 HarmonyOS 保存到页面栈的空间当中。页面栈顾名思义就是保存页面的栈结构空间,栈结构是先进后出,所以呢,我们最早访问的登录页就被压到了栈的最底层,而当前正在访问的商品A的详情页就在栈顶。也就是说,谁在栈顶,当前显示的就是谁的页面。那么 HarmonyOS 为啥要把这些访问过的页面保存起来,而不是直接销毁掉呢?放在这里不占用内存吗?这其实是我们的页面功能需要去用到这些历史页面。一般商品详情页都会有返回按钮,当点击返回按钮,应该返回到之前访问过的搜索列表页,有了页面栈,想要实现这个功能就非常简单了。只需要在点击返回时,把栈顶的这个页面移除,这样一来,紧挨着栈顶的搜索列表页就成为了新的栈顶页面,现在显示的就是搜索列表页,从而也就实现了返回的效果。如果现在想做页面跳转,过程就相反,比如在搜索列表页点击商品B,只需要把商品B的详情页创建出来,然后压入栈里,现在栈顶就是商品B的详情页,从而实现了跳转效果。简单来讲,如果想实现创建页面,就压入栈;如果想实现返回,就把栈顶页面弹出栈,即可。

  1. 页面栈的最大容量:

    页面栈的最大容量上限为 32 个页面。就是说如果我们不断的去访问新的页面,往栈里压入页面,可能就会达到上限,这时候再想访问这个页面,再想往里面去压栈,就会报错,这时候就不得不去调用 router.clear() 方法去清空页面栈,就会把历史页面干掉,释放内存。但是,一旦把历史页面干掉,再想返回前一个页面就访问不了了。所以 router.clear() 要慎重使用。我们在开发的过程中一定要想办法控制页面栈里的页面数量,不要让它达到上限,而不是说等达到上限去清空。

  2. 怎么去控制页面栈里的页面数量呢?就要使用页面栈不同的跳转行为模式。Router 有两种页面跳转模式:

    • router.pushUrl():目标页不会替换当前页,而是压入页面栈。比如当前在商品A的详情页,如果点击商品B的图片,就需要压入栈,就需要创建一个商品B的页面,把商品B的详情页压入栈顶,这时候,原有的商品A的详情页不会被移除,而是压到栈的内部,成为一个历史页面,因此点返回按钮,用 router.back() 就会返回到历史页面商品A的详情页。但是,这种实现方式会导致栈里的页面会越来越多。

    • router.replaceUrl():目标页替换当前页,当前页会被销毁并释放资源。也就是说从商品A的详情页跳转到商品B的详情页,这时候商品A的详情页就变成了历史页,会直接被销毁,而不是在栈内保存。这样一来,内存就节省出来,但是如果想从商品B的详情页返回到商品A的详情页,就返回不了了。

  3. 何时使用 router.pushUrl(),何时又使用 router.replaceUrl() 呢?

    举个例子,比如说,我们的登录页,只有在第一次打开的时候才需要,只要不退出,就不用再登录。所以登录页基本上就访问一次,而且也不需要返回,登录页保存在历史页面栈里没有任何意义,所以在登录成功以后,跳转到首页时,就可以使用 router.replaceUrl() 把登录页销毁;如果我们从首页跳转到搜索列表页,如果这时候点返回,返回到首页,所以我们的首页应该在页面栈里保存,作为一个历史页面,就要用 router.pushUrl()

  4. 如果商品A的详情页和商品B的详情页来回切换,如果用到 router.pushUrl(),会导致页面栈的容量一会儿就满了,就要用到页面实例模式,Router 有两种页面实例模式:

    • Standard:标准实例模式,每次跳转都会新建一个目标页并压入栈顶。默认就是这种模式。

    • Single:单实例模式,顾名思义,每一个页面只会存在一份,如果目标页已经在栈中,则离栈顶最近的同Url页面会被移动到栈顶并重新加载。

结合合适的跳转模式(router.pushUrl()router.replaceUrl())和实例模式(StandardSingle),就能够控制页面栈里的页面数量,避免达到上限。

二、Router API 用法

  1. 首先要导入 HarmonyOS 提供的 Router 模块:

    import router from '@ohos.router';
    
  2. 然后利用 router 实现跳转、返回等操作:

    router.pushUrl({url: 'pages/PageA',params: { id: 1 }},router.RouterMode.Single,err => {if (err) {console.log('路由失败。')}}
    )
    
    • RouterOptions

      • url:目标页面路径
      • params:传递的参数(可选)
    • RouterMode

      • Standard:标准实例模式
      • Single:单实例模式
    • 异常响应回调函数

      • 错误码 100001:内部错误,可能是渲染失败
      • 错误码 100002:路由地址错误
      • 错误码 100003:路由栈中页面超过32
  3. 目标页获取传递过来的参数

    params: any = router.getParams()
    
  4. 目标页返回上一页

    router.back()
    
  5. 目标页返回指定页,并携带参数

    router.back({url: 'pages/Index',params: { id: 10 }
    })
    

三、示例

  1. 代码目录结构

    |____src
    | |____main
    | | |____resources
    | | | | |____profile
    | | | | | |____main_pages.json
    | | | | |____media
    | | | | | |____back.png
    | | |____ets
    | | | |____components
    | | | | |____CommonComponents.ets
    | | | |____pages
    | | | | |____PageD.ets
    | | | | |____PageC.ets
    | | | | |____PageB.ets
    | | | | |____PageA.ets
    | | | | |____Index.ets
    
  2. main_pages.json

    {"src": ["pages/Index","pages/PageA","pages/PageB","pages/PageC","pages/PageD"]
    }
    
  3. CommonComponents.ets

    import router from '@ohos.router'@Component
    export struct Header {@State params: any = router.getParams()build() {Row({ space: 5 }) {Image($r('app.media.back')).width(30).onClick(() => {// 返回前的警告router.showAlertBeforeBackPage({message: 'Show Alert Before Back Page'})// 返回上一页router.back()})if (this.params) {Text(`Params id: ${this.params.id}`).fontSize(28).fontWeight(FontWeight.Bold)}}.width('98%').height(30)}
    }
    
  4. Index.ets

    import router from '@ohos.router'class RouterInfo {// 页面路径url: string// 页面标题title: stringconstructor(url: string, title: string) {this.url = urlthis.title = title}
    }@Entry
    @Component
    struct Index {@State message: string = '页面列表'private routers: RouterInfo[] = [new RouterInfo('pages/PageA', 'A页面'),new RouterInfo('pages/PageB', 'B页面'),new RouterInfo('pages/PageC', 'C页面'),new RouterInfo('pages/PageD', 'D页面')]build() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold).height(80)List({ space: 15 }) {ForEach(this.routers,(router, index) => {ListItem() {this.RouterItem(router, index + 1)}})}.layoutWeight(1).alignListItem(ListItemAlign.Center).width('100%')}.width('100%').height('100%')}@BuilderRouterItem(r: RouterInfo, i: number) {Row() {Text(i + '. ').fontSize(20).fontColor(Color.White)Text(r.title).fontSize(20).fontColor(Color.White)}.width('90%').padding(12).backgroundColor('#38F').borderRadius(20).shadow({ radius: 6, color: '#4F000000', offsetX: 2, offsetY: 2 }).onClick(() => {// router 跳转router.pushUrl({url: r.url,params: { id: i }},router.RouterMode.Single,err => {if (err) {console.log(`路由失败,errCode: ${err.code} errMsg: ${err.message}`)}})})}
    }
    
  5. PageA.ets

    import { Header } from '../components/CommonComponents'@Entry
    @Component
    struct PageA {@State message: string = 'Page A'build() {Column() {Header()Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold)}.width('100%')}.height('100%')}.width('100%')}
    }
    
  6. 运行效果

请添加图片描述

四、总结

  1. 页面栈的最大容量上限为 32 个页面,使用 router.clear() 方法可以清空页面栈,释放内存。

  2. Router 有两种页面跳转模式,分别是:

    • router.pushUrl():目标页不会替换当前页,而是压入页面栈,因此可以用 router.back() 返回当前页。
    • router.replaceUrl():目标页替换当前页,当前页会被销毁并释放资源,无法返回当前页。
  3. Router 有两种页面实例模式,分别是:

    • Standard:标准实例模式,每次调整都会新建一个目标并压入栈顶。默认就是这种模式。
    • Single:单实例模式,如果目标页已经在栈中,则离栈顶最近的同 url 页面会被移动到栈顶并重新加载。
  4. router 的使用步骤:

    1. 导入 router 模块
    2. 使用 router 的 API

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

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

相关文章

茄子科技前端实习面经

需求沟通中有没有碰到什么问题,怎么解决的问项目用echarts有没有碰见什么问题vue2和vue3的区别defineproperty可以监听function和数组吗有碰见过双向数据绑定单向数据流的情况吗?父子传参父子传参有哪些vuex的理解异步数据怎么在vux怎么改vuex刷新数据会…

水下蓝牙耳机哪个好?必看4款购买单,拒绝踩雷!

在当今的科技时代,无线蓝牙耳机已经成为了我们生活中不可或缺的一部分。无论是运动、工作还是休闲娱乐,一款好的蓝牙耳机都能为我们带来极大的便利和乐趣。然而,在水下使用蓝牙耳机却是一个相对特殊的应用场景,需要考虑到防水、防…

力扣刷题Days25-45. 跳跃游戏 II(js)

目录 1,题目 2,代码 贪心算法正向查找 3,学习 解题思路 具体代码处理 数组遍历的最后边界的处理: 1,题目 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向…

Nuclei Poc开发

1、Poc开发工具介绍 Nuclei:https://nuclei.projectdiscovery.io/ Cloud Platfrom云平台:https://cloud.projectdiscovery.io/ 2、目标站点简介 目标演示站点:http://glkb-jqe1.aqlab.cn/nacos/#/login 指纹:Nacos 已知常用漏洞…

日本大带宽服务器优缺点分析

日本大带宽服务器是很多用户的选择,那么日本大带宽服务器优缺点都是什么?Rak部落小编为您整理发布日本大带宽服务器优缺点分析。 日本大带宽服务器的优点主要包括高速的数据传输、亚太地区的良好覆盖、可靠性和稳定性强以及先进的硬件和光纤网络技术。 日本大带宽服…

基于springboot+vue的农产品直卖平台

博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战,欢迎高校老师\讲师\同行交流合作 ​主要内容:毕业设计(Javaweb项目|小程序|Pyt…

20个SpringSecurity框架核心组件详解

Spring Security 是一个功能强大且灵活的身份验证和访问控制框架,在很多项目中都会采用该框架来实现权限控制功能,兄弟们在开发中需要搞清楚底层实现逻辑,或者面试时会被面试官频频追问底层源码,今天的文章,V哥总结了S…

(3)乾卦_学习笔记

大象 天行健,君子当自强不息。 健:持久的运行不息:跌倒了爬起来 从乾卦这里,先求自己。人是靠自己的,如果靠环境,那还学习干什么。一个人最了不起的,不是去控制别人,而是做一个好…

牛客竞赛语法入门班顺序结构习题(重现赛)(1031-1040)

本篇包含: 1、1031-时间转换 2、1032-温度转换 3、1033-计算机内存 4、1034-[NOIP2017]成绩 5、1035-KiKi的最高分 6、1036-组队比赛 7、1037-平方根 8、1038-长方体 9、1039-使徒袭来 10、1040-白兔的分身术 本篇包含考点: 1、小时、分钟和秒的转换 2、…

备战蓝桥杯Day35 - 动态规划 - 01背包问题

问题描述 隐含前提: 1.物体是不可分的,要么装,要么不装,不能只装一部分。 2.物体顶多使用一次。 动态规划思路 我在b站上看的闫氏dp分析大法的视频,他对dp问题做了总结归纳。 从集合的角度分析dp问题。求出有限集…

【python导入包解决方案】linux环境下python文件无法导入其他文件夹中的python文件的解决方案

出错描述 Test: │ ├─main │ main.py └─pakfunc.py如上图,我有个python项目叫Test,我的期望是pak文件夹当作自定义包,main文件夹里面是我的主程序,然后去调pak的包。现在我在main.py文件里面导入func.py里面的某个函…

24.3.24 《CLR via C#》 笔记10

第十三章 接口 类和接口继承 CLR不支持多继承,因此所有托管编程语言都不支持任何类都从且只能从一个类派生(最终从Object类派生)定义接口实际只是对一组方法进行了统一的命名,类通过指定接口名称来继承接口,且必须显式…

一款炫酷的python形状绘制动画库

这个库让复杂数学概念的可视化变得既简单又有趣,无论是线性代数、微积分,还是更高级的数学主题,Manim都能让它们栩栩如生,特别适合于制作数学视频和演示文稿。 特点 动画生成: Manim库提供了一套丰富的工具和方法&…

Install Docker

Docker Desktop 直接安装 Docker Desktop Docker Desktop includes the Docker daemon (dockerd), the Docker client (docker), Docker Compose, Docker Content Trust, Kubernetes, and Credential Helper. Linux下安装Docker CE 参考官方文档 参见阿里云的文档 # step 1…

Git 使用笔记

基本操作: 初始化 (git init) 使用背景和作用: 在本地建立一个文件夹后,基于这个文件夹进行git 操作,赋予git操作本文件夹的权限 。查看当前文件夹状态(git status) 每次打开文件夹…

ubuntu22.04基于docker部署k8s1.29.x 高可用集群

参考:https://mp.weixin.qq.com/s/7i68jmvi2eo_6wlqYEOupQ 操作系统:Ubuntu 22.04 nginx代理配置 代理IP :192.168.0.10 vim /etc/nginx/nginx.conf stream {upstream kube-apiserver {server 192.168.0.11:6443 max_fails3 fail_ti…

k8s中,pod服务的状态和pod里面的容器的状态关系

Pod 的状态和 Pod 里面的容器的状态是密切相关的。Pod 是 Kubernetes 中最小的调度单元,一个 Pod 可以包含一个或多个容器。Pod 的状态反映了 Pod 中所有容器的状态情况。 Pod 的状态包括: Pending(等待):Pod 已经被创…

【WEEK4】Learning Objectives and Summaries【SpringMVC】【English Version】

Learning Objectives: Getting Started with SpringMVC in Four Weeks - Week 4 Learning Content: Reference video tutorials【狂神说Java】SpringMVC最新教程IDEA版通俗易懂Integrate the SSM framework Spring SpringMVC environmentPerform add, delete, check and modi…

算法系列--动态规划--子序列(1)

💕"深思熟虑的结果往往就是说不清楚。"💕 作者:Mylvzi 文章主要内容:算法系列–动态规划–子序列(2) 今天带来的是算法系列--动态规划--子序列(1),是子序列问题的开篇!带大家初识子序列问题 一.什么是子序列问题 我们…

6.volatile与JMM

文章目录 被 volatile 修饰的变量有两大特点volatile 的内存语义volatile 凭什么可以保证有序性和可见性? 内存屏障(面试重点)解读 volatile 的两大特性内存屏障 volatile 特性两大类读屏障(Load Barrier)写屏障(Store Barrier) 四小类C源码分析四类屏障特点 如何保证有序性?…