1、概念

页面路由是指在应用程序中实现不同页面之间的跳转和数据传递。在 ArkTs 中,用户操作的每个页面都被存储在一个页面栈中,历史页面并没有被销毁。这样我们在返回操作时就只需要把栈顶的移除即可实现返回上一页效果。每次访问新的页面只需要创建新的页面,然后压入栈顶即可。那么问题来了,如果用户一直访问新页面,那么是不是就会一直压入栈顶,内存消耗就会递增。问题确实存在,在 HarmonyOS 中,规定了页面栈的最大容量上限为 32 个页面,超出这个上限就会报错。而使用 router.clear() 方法可以清空页面栈,达到释放内存的效果,但是要慎用,一旦清空,页面上有些功能可能会报错引发程序异常。因此,如何处理页面跳转方式,正确实现页面跳转就需要使用不同的页面路由方式+页面创建模式。

2、Router 页面跳转模式与页面实例模式

Router的两种页面跳转模式

  • router.pushUrl() : 目标页面不替换当前页,而是压入页面栈,因此可以使用 router.back() 返回当前页面
  • router.replaceUrl() : 目标页面替换当前页面,当前页面被销毁并释放资源,无法返回当前页。

Router的两种页面实例模式

  • Standard : 标准实例模式,每次跳转都会新建一个目标页并压入栈顶,也是默认的模式
  • Single : 单例模式,如果目标页面已经在页面栈中,则离栈顶最近的同个Url页面会被移动到栈顶,页面重新加载显示。

2、页面路由使用

在这里插入图片描述

3、案例演示

之前的内容我们实现了好几个功能页面,现在我们把这些页面都关联起来,通过主界面实现不同页面的跳转和切换。

主要界面

  • 主页面 创建一个新的主页
  • 图片动态缩放页面
  • 商品列表页面
  • 钱包钱币数量页面
  • 任务统计页面

1、创建主页

在 pages/Demo 目录中创建 Homepage 页面,Homepage 页面代码实现如下:

完整代码


import router from '@ohos.router';

//页面跳转类
class RouterSkip{
  //页面标题
  pageName:string
  //页面路径
  pageUrl:string

  constructor(pageName:string,pageUrl:string) {
    this.pageName=pageName;
    this.pageUrl=pageUrl
  }
}


@Entry
@Component
struct HomePage {
  @State message: string = '页面列表'

  private pageList:RouterSkip[]=[
    new RouterSkip('图片缩放','pages/Demo/ImagePage'),
    new RouterSkip('商品列表','pages/Demo/ListPage'),
    new RouterSkip('钱包钱币','pages/Demo/StatePage'),
    new RouterSkip('任务统计','pages/Demo/TaskPage'),
  ]


  build() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .height(80)

        List({space:15}){
          ForEach(
            this.pageList,
            (item,id)=>{
              ListItem(){
                this.RouterItem(item,id+1)
              }
            }
          )
        }
        .layoutWeight(1)
        .width('100%')
        .alignListItem(ListItemAlign.Center)
      }
      .width('100%')
      .height('100%')
  }

  @Builder
  RouterItem(r:RouterSkip,i:number){
    Row(){
Text(i+'.')
  .fontSize(20)
  .fontColor(Color.Yellow)

      Blank()
      Text(r.pageName)
        .fontSize(20)
        .fontColor(Color.Yellow)
    }
    .width('90%')
    .padding(12)
    .backgroundColor('#2B2B2B')
    .borderRadius(20)
    .shadow({radius:6,color:'#FFF',offsetX:2,offsetY:2})
    .onClick(()=>{
      router.pushUrl(
        {
          url:r.pageUrl,
          params:{id:i}
        },
        router.RouterMode.Single,
        err=>{
          if(err){
            console.log('路由失败,errCode:'+err.code+'errMsg:'+err.message)
          }
        }
      )
    })
  }


}


代码解释

  • 导入路由模块
import router from '@ohos.router';
  • 页面跳转类
class RouterSkip {
  // 页面标题
  pageName: string
  // 页面路径
  pageUrl: string

  constructor(pageName: string, pageUrl: string) {
    this.pageName = pageName;
    this.pageUrl = pageUrl
  }
}

RouterSkip 类用于封装页面的标题和路径。
pageName 存储页面标题。
pageUrl 存储页面路径。构造函数 constructor 初始化这两个属性。

  • 定义主页组件
@Entry
@Component
struct HomePage {
  @State message: string = '页面列表'

  private pageList: RouterSkip[] = [
    new RouterSkip('图片缩放', 'pages/Demo/ImagePage'),
    new RouterSkip('商品列表', 'pages/Demo/ListPage'),
    new RouterSkip('钱包钱币', 'pages/Demo/StatePage'),
    new RouterSkip('任务统计', 'pages/Demo/TaskPage'),
  ]
  • 构建页面布局
  build() {
    Column() {
      Text(this.message)
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .height(80)

      List({ space: 15 }) {
        ForEach(
          this.pageList,
          (item, id) => {
            ListItem() {
              this.RouterItem(item, id + 1)
            }
          }
        )
      }
      .layoutWeight(1)
      .width('100%')
      .alignListItem(ListItemAlign.Center)
    }
    .width('100%')
    .height('100%')
  }
  • 自定义页面列表项构件
  @Builder
  RouterItem(r: RouterSkip, i: number) {
    Row() {
      Text(i + '.')
        .fontSize(20)
        .fontColor(Color.Yellow)

      Blank()
      Text(r.pageName)
        .fontSize(20)
        .fontColor(Color.Yellow)
    }
    .width('90%')
    .padding(12)
    .backgroundColor('#2B2B2B')
    .borderRadius(20)
    .shadow({ radius: 6, color: '#FFF', offsetX: 2, offsetY: 2 })
    .onClick(() => {
      router.pushUrl(
        {
          url: r.pageUrl,
          params: { id: i }
        },
        router.RouterMode.Single,
        err => {
          if (err) {
            console.log('路由失败,errCode:' + err.code + 'errMsg:' + err.message)
          }
        }
      )
    })
  }

使用 @Builder 装饰器定义 RouterItem 方法,用于构建页面项。
Row 布局容器,用于水平排列子组件。
Text(i + ‘.’) 显示序号。
Blank() 用于添加空白间隔。
Text(r.pageName) 显示页面标题。
设置样式:宽度、内边距、背景色、圆角、阴影。
onClick 事件处理程序,使用 router.pushUrl 方法进行页面跳转。
url: r.pageUrl 指定目标页面的路径。
params: { id: i } 传递参数。
router.RouterMode.Single 设置路由模式。
err => { … } 处理路由失败的情况。

2、路由配置

页面要实现跳转,还需要再 resources/base/profile 文件夹下的 main_pages.json 中配置对应的路由,如下图所示:

在这里插入图片描述
小技巧

通常我们在创建页面的时候有两种方式,一种是创建 ArkTs 文件,如下:
在这里插入图片描述
这种情况创建的页面文件在 main_pages.json 中是没有路由路径配置的,需要自己手动添加。而通过创建页面的方式创建的页面会自动生成页面路由,不需要手动配置。如下所示:
在这里插入图片描述

3、给子页面添加返回功能导航栏

自定义组件(头部菜单导航) 这节中,我们封装了一个 HeaderMenu 菜单导航组件,我么只要在子页面加上这个组件即可。以 ListPage 页面为例:

先导入组件

import {HeaderMenu} from '../../components/HeadMenu'

然后再最顶上引用组件
在这里插入图片描述
按照这种方法把剩下的几个页面全部添加上 HeaderMenu 导航栏。

4、给HeaderMenu 添加返回事件

之前的HeaderMenu 没有添加返回的点击事件 ,我们机上返回事件,代码如下:


import router from '@ohos.router'
@Component
export struct HeaderMenu {
  private title:ResourceStr
  build(){
    Row() {
      Image($r('app.media.back'))
        .width(30)
        .onClick(()=>{
          //返回上一页
          router.back()
        })
      Text(this.title)
        .fontSize(30)
        .fontWeight(FontWeight.Bold)
      Blank()
      Image($r('app.media.refresh'))
        .width(30)
    }
    .width('100%')
    .height(30)
  }
}

5、拓展:获取页面中的参数

路由同时获取页面的参数,对 HeaderMenu 改造如下所示:


import router from '@ohos.router'
@Component
export struct HeaderMenu {
  private title:ResourceStr

  @State params:any=router.getParams();
  build(){
    Row() {
      Image($r('app.media.back'))
        .width(30)
        .onClick(()=>{
          //返回上一页
          router.back()


        })
      if(this.params&&this.title)
      {
        Text(this.params.id+'.'+this.title)
          .fontSize(30)
          .fontWeight(FontWeight.Bold)
      }

      Blank()
      Image($r('app.media.refresh'))
        .width(30)
    }
    .width('100%')
    .height(30)
  }
}

在这里插入图片描述

6、运行效果

在这里插入图片描述

7、添加返回前弹窗提示

在这里插入图片描述

在这里插入图片描述

4、总结

本节主要讲解了页面路由的原理和种类,包括两种路由方式和两种页面创建方式,并给出了实际案例实现。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐