【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,一经查实,立即删除!

相关文章

水下蓝牙耳机哪个好?必看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 已知常用漏洞…

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

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

牛客竞赛语法入门班顺序结构习题(重现赛)(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形状绘制动画库

这个库让复杂数学概念的可视化变得既简单又有趣,无论是线性代数、微积分,还是更高级的数学主题,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) 每次打开文件夹…

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

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

6.volatile与JMM

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

huggingface的transformers训练gpt

目录 1.原理 2.安装 3.运行 ​编辑 4.数据集 ​编辑 4.代码 4.1 model init​编辑 forward: 总结: 关于loss和因果语言模型: ​编辑 交叉熵:​编辑 记录一下transformers库训练gpt的过程。 transformers/examples/…

klipper源码分析之simulavr测试

分析Klipper源码,有时需要结合下位机一起分析,这样才能更加全面的了解Klipper的工作原理。如果手头上有打印机主板,电脑当做上位机运行Klipper,这样是比较方便。如果手头上没有打印机主板,可以用simulavr模拟AVR下位机…

Linux常见指令解析一

Linux常见指令解析一 常见指令1. ls 指令2.pwd 命令3.cd 命令4.touch 命令5.mkdir 命令6.rmdir指令 && rm 指令7.man 指令8.cp 指令9.cat 命令 && tac 命令10.mv 指令11.more 指令12.less 指令13.head 指令14.tail 指令15.cal 指令 常见指令 1. ls 指令 语法…

Vscode创建php项目

1.安装中文插件(可安装可不安装) 2.安装主题(可安装可不安装) 3.安装和php相关的插件 4.打开文件夹 5.路由操作 查看项目中的route路由 浏览器中访问think 隐藏index.php入口文件 访问ThinkPHP5.1开发手册,复制apa…

【Python实战】——神经网络识别手写数字

🍉CSDN小墨&晓末:https://blog.csdn.net/jd1813346972 个人介绍: 研一|统计学|干货分享          擅长Python、Matlab、R等主流编程软件          累计十余项国家级比赛奖项,参与研究经费10w、40w级横向 文…

鸿蒙APP应用开发教程—超详细的项目结构说明

1. 新建项目 打开DevEco Studio, 选择 Create Project: 1.1 选择模版 Create Project - Choose Template 1.2 配置项目 Create Project - Configure Project 如果使用的是 DevEco 3.X 版本, 可以根据 Compile SDK版本选择不同的模式, 比如: 3.0.0(API 8)及更早 - 仅支持 …

数字图像处理学习笔记(五)

数字图像处理学习笔记(五) 表示与描述表示链码最小周长多边形的多边形近似(MPP)标记边界片段骨骼(表示平面区域结构形状) SIFT原理(尺度不变特征变换匹配算法:Scale-invariant feature transform)SIFT算法分…

有名的爬虫框架 colly 的特性及2个详细采集案例

一. Colly概述 前言:colly 是 Go 实现的比较有名的一款爬虫框架,而且 Go 在高并发和分布式场景的优势也正是爬虫技术所需要的。它的主要特点是轻量、快速,设计非常优雅,并且分布式的支持也非常简单,易于扩展。 框架简…

Linux之时间子系统(四): tick 层模块(periodic 和dynamic )

一、时间子系统的软件架构 二、tick 层模块的文件 tick-common.c tick-oneshot.c tick-sched.c tick-broadcast.c tick-broadcast-hrtimer.c 这三个文件属于tick device layer。 tick-common.c文件是periodic tick模块,用于管理周期性tick事件。 tick-oneshot.c文…