【HarmonyOS】ArkUI - 页面路由

news/2024/7/21 9:30:18 标签: harmonyos, 华为, 鸿蒙, arkts, 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: string
    
      constructor(url: string, title: string) {
        this.url = url
        this.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%')
      }
    
      @Builder
      RouterItem(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.niftyadmin.cn/n/5448882.html

相关文章

隐私计算实训营学习四:SecretFlow的安装和部署

文章目录 一、SecretFlow安装二、SecretFolw部署模式简介三、SecretFlow部署-仿真模式四、SecretFlow部署-生产模式 一、SecretFlow安装 SecretFlow运行要求: Python > 3.8操作系统:CentOS7、Anolis8、Ubuntu 18.04/20.04、macOS 11.1、WSL2资源&am…

情感计算:大模型在情感识别与交互优化中的作用

情感计算:大模型在情感识别与交互优化中的作用 1. 背景介绍 情感计算(Affective Computing)是人工智能领域的一个重要分支,它致力于使计算机能够识别、理解、处理和模拟人类的情感。随着深度学习、大数据和计算能力的飞速发展&a…

51单片机学习笔记——LED闪烁和流水灯

任务分析 首先要知道LED闪烁主要是怎么工作的,闪烁亮灭自然是一下为高一下为低,亮灭的频率则需要延时来进行控制。 上节已经知道了如何点亮那延时如何做呢首先先编写主框架 这样是否可以通过循环将LED灯一直循环闪烁。 以为while一直在循环所以其实是可…

谷粒商城——缓存的读写一致性

1. 对于实时性要求很强的数据,如果修改完数据库,需要保证缓存中的数据也更新为相应的最新值。此时需要在更新数据库之前加上写锁,在更新/删除完缓存后才释放写锁。 伪代码如下: lock.writeLock().lock(); updateDB(); updateCac…

113 链接集10--ctrl+左键单击多选

1.ctrl左键单击多选&#xff0c;单击单选 精简代码 <div class"model-list"><divmousedown.prevent"handleClick(item, $event)"class"model-list-item"v-for"item in modelList":key"item.id":class"{ model…

macOS访问samba文件夹的正确姿势,在哪里更改“macOS的连接身份“?还真不好找!

环境&#xff1a;路由器上需要身份认证的Mini NAS macOS Sonoma 14 这是一个非常简单的问题&#xff0c;但解决方法却藏得比较深&#xff0c;不够直观&#xff0c;GPT也没有给出明确的解决提示&#xff0c;特意记录一下。 macOS很多地方都很自动&#xff0c;有时候让人找不到设…

SpringBoot Starter解析

conditional注解解析 介绍 基于条件的注解作用: 根据是否满足某一个特定条件决定是否创建某个特定的bean意义: Springboot实现自动配置的关键基础能力 常见的conditional注解 ConditionalOnBean: 当容器中存在某个Bean才会生效ConditionalOnMissingBean: 不存在某个Bean才会…

ARM:串口控制点灯

uart4.c #include "uart4.h"char buf[51] {0}; // led数据初始化 void led_init() {// 设置GPIOE/GPIOF时钟使能RCC->MP_AHB4ENSETR | (0x3 << 4);// 设置PE10/PE8/PF10为输出模式GPIOE->MODER & (~(0x3 << 20));GPIOE->MODER | (0x1 <…