HarmonyOS 页面路由Router切换组件导航Navigation

0 阅读4分钟

一、路由Router

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

1、页面跳转

Router模块提供了两种跳转模式,分别是pushUrlreplaceUrl

  • pushUrl:目标页面不会替换当前页,而是压入页面栈。
  • replaceUrl:目标页面会替换当前页,并销毁当前页。
//替换当前页面
router.replaceUrl({
  url: FieldSingPage
})

//跳转新页面
router.pushUrl({
  url: FieldSingPage
})

//跳转新页面并传参
router.pushUrl({
  url: HouseSearchPage,
  params: {
    trade: this.trade
  }
})

2、页面返回

当用户在一个页面完成操作后,通常需要返回到上一个页面或者指定页面,这就需要用到页面返回功能。

返回上一个页面

这种方式会返回到上一个页面,即上一个页面在页面栈中的位置。

router.back()

//返回上一页,并传递参数
router.back({
  url:"",
  params: {
    verificationCode: this.verificationCode
  }
})
返回指定页面

这种方式可以返回到指定页面,需要指定目标页面的路径。

router.back({
  url: 'pages/FieldSingPage'
});

3、接受页面传递过来的参数

在跳转的新页面或者返回页面的指定页面接收传递过来的参数,通过router.getParams()获取到传递过来的所有参数,通过 key 值获取对应的参数数据

onPageShow(): void {
  //接收验证码页面返回的验证码
  let params = router.getParams() as Record<string, string>
  if (params) {
  this.smsCode = params["verificationCode"]
  //验证码回到登录页调用登录方法
  this.loginAction()
}

4、在module.json5中配置页面路径文件

使用 router跳转到某个页面需要在 module.json5中配置页面路径
{
  "module": {
    ...
    ... //其他属性
    ...
    "pages": "$profile:main_pages"
    }
}
这里可以在resources/base/profile新建文件main_pages.json 文件,在此文件中配置页面路径。
{
  "src": [
    "pages/Index",
    "pages/login/LoginPage",
    "pages/house/HouseSearchPage",
    "pages/house/HouseDetailsPage",
    "pages/WoodenFishGame",
    "pages/house/AddHousePage",
  ]
}

二、组件导航 Navigation

组件导航(Navigation)主要用于实现页面间以及组件内部的页面跳转,支持在不同组件间传递跳转参数,提供灵活的跳转栈操作,从而更便捷地实现对不同页面的访问和复用。Navigation组件主要包含导航页和子页。

Navigation路由相关的操作都是基于页面栈NavPathStack提供的方法进行,每个Navigation都需要创建并传入一个NavPathStack对象,用于管理页面。

1、导航页

导航页是一般是持续的入口页面,使用导航组件Navigation作为主页面的根容器,传递NavPathStack参数,

通过NavPathStack对象来控制页面的页面跳转、页面返回、页面替换、参数获取等功能

@Entry
@Component
struct Index {
  // 创建一个页面栈对象并传入Navigation
  pageStack: NavPathStack = new NavPathStack();

  build() {
    Navigation(this.pageStack) {
      //页面组件
    }
  }
}
页面跳转

NavPathStack通过Push相关的接口去实现页面跳转的功能,主要分为以下三类:

  1. 普通跳转,通过页面的name去跳转,并可以携带param。
this.pageStack.pushPath({ name: "PageOne", param: "PageOne Param" });
this.pageStack.pushPathByName("PageOne", "PageOne Param");
  1. 带返回回调的跳转,跳转时添加onPop回调,能在页面出栈时获取返回信息,并进行处理。
this.pageStack.pushPathByName('PageOne', "PageOne Param", (popInfo) => {
  console.log('Pop page name is: ' + popInfo.info.name + ', result: ' + JSON.stringify(popInfo.result));
});
  1. 带错误码的跳转,跳转结束会触发异步回调,返回错误码信息。
this.pageStack.pushDestination({name: "PageOne", param: "PageOne Param"})
  .catch((error: BusinessError) => {
    console.error(`Push destination failed, error code = ${error.code}, error.message = ${error.message}.`);
  }).then(() => {
    console.info('Push destination succeed.');
  });
this.pageStack.pushDestinationByName("PageOne", "PageOne Param")
  .catch((error: BusinessError) => {
    console.error(`Push destination failed, error code = ${error.code}, error.message = ${error.message}.`);
  }).then(() => {
    console.info('Push destination succeed.');
  });
页面返回

NavPathStack通过Pop相关接口去实现页面返回功能。

// 返回到上一页
this.pageStack.pop();
// 返回到上一个PageOne页面
this.pageStack.popToName("PageOne");
// 返回到索引为1的页面
this.pageStack.popToIndex(1);
// 返回到根首页(清除栈中所有页面)
this.pageStack.clear();
页面替换

NavPathStack通过Replace相关接口去实现页面替换功能。

// 将栈顶页面替换为PageOne
this.pageStack.replacePath({ name: "PageOne", param: "PageOne Param" });
this.pageStack.replacePathByName("PageOne", "PageOne Param");
// 带错误码的替换,跳转结束会触发异步回调,返回错误码信息
this.pageStack.replaceDestination({name: "PageOne", param: "PageOne Param"})
  .catch((error: BusinessError) => {
    console.error(`Replace destination failed, error code = ${error.code}, error.message = ${error.message}.`);
  }).then(() => {
    console.info('Replace destination succeed.');
  })

2、子页面

NavDestination是Navigation子页面的根容器,用于承载子页面的一些特殊属性以及生命周期等。

获取Navigation页面传递到子页面的参数

NavDestination子页第一次创建时会触发onReady回调,可以获取此页面对应的参数。

@Builder
  export function AddFieldPageBuilder() {
  AddFieldPage()
}

@Component
  struct AddFieldPage {
    pathStack: NavPathStack | undefined = undefined;
    pageParam: string = '';


    build() {
      NavDestination() {
        ...
      }.onReady((context: NavDestinationContext) => {
        this.pathStack = context.pathStack;
        this.pageParam = context.pathInfo.param as string;
      })
    }
  }

其他业务场景,可以通过主动调用NavPathStack的Get相关接口去获取指定页面的参数。

// 获取栈中所有页面name集合
this.pageStack.getAllPathName();
// 获取索引为1的页面参数
this.pageStack.getParamByIndex(1);
// 获取PageOne页面的参数
this.pageStack.getParamByName("PageOne");
// 获取PageOne页面的索引集合
this.pageStack.getIndexByName("PageOne");
子页面的配置

每个子页也需要配置到系统配置文件route_map.json中

{
  "module": {
    ...
    ... //其他属性
    ...
    "routerMap": "$profile:route_map"
    }
}

在resources/base/profile新建文件route_map.json 文件,在此文件中配置页面信息,pageSourceFile是页面路径,buildFunction表示页面的 builder方法名称。

{
  "routerMap": [
    {
      "name": "AddFieldPage",
      "pageSourceFile": "src/main/ets/pages/field/AddFieldPage.ets",
      "buildFunction": "AddFieldPageBuilder",
      "data": {
        "description": "新增外勤记录"
      }
    },
    {
      "name": "SelectBuildingPage",
      "pageSourceFile": "src/main/ets/pages/house/SelectBuildingPage.ets",
      "buildFunction": "SelectBuildingPageBuilder",
      "data": {
        "description": "选择楼盘"
      }
    }
  ]
}

三、Router切换Navigation

Router切换Navigation主要需要主要以下几点,页面配置和生命周期有点区别,Navigation具有更强的功能和自定义能力,推荐使用该组件作为应用的路由框架。目前最新版本的 api中已经废弃Router方法。

1、页面配置

Router和Navigation都需要在配置文件中配置页面路径、信息,Navigation是需要配置子页面信息。

  • Router中每一个页面都需要在main_page.json中声明
// main_page.json
{
  "src": [
    "pages/Index",
    "pages/pageOne",
    "pages/pageTwo"
  ]
}
  • Navigation每个子页也需要配置到系统配置文件route_map.json中
// 工程配置文件module.json5中配置 {"routerMap": "$profile:route_map"}
// route_map.json
{
  "routerMap": [
    {
      "name": "pageOne",
      "pageSourceFile": "src/main/ets/pages/PageOne.ets",
      "buildFunction": "PageOneBuilder",
      "data": {
        "description": "this is pageOne"
      }
    }
  ]
}

2、路由操作

1、Router通过@ohos.router模块提供的方法来操作页面;

2、Navigation通过页面栈对象NavPathStack提供的方法来操作页面,需要创建一个栈对象并传入Navigation中。

3、生命周期

Router页面主要有以下四个生命周期:

// 页面创建后挂树的回调
aboutToAppear(): void {
}


// 页面销毁前下树的回调  
aboutToDisappear(): void {
}


// 页面显示时的回调  
onPageShow(): void {
}


// 页面隐藏时的回调  
onPageHide(): void {
}

Navigation作为路由容器,其生命周期承载在NavDestination组件上,以组件事件的形式开放。

  • aboutToAppear:在创建自定义组件后,执行其build()函数之前执行(NavDestination创建之前),允许在该方法中改变状态变量,更改将在后续执行build()函数中生效。
  • onWillAppear:NavDestination创建后,挂载到组件树之前执行,在该方法中更改状态变量会在当前帧显示生效。
  • onAppear:通用生命周期事件,NavDestination组件挂载到组件树时执行。
  • onWillShow:NavDestination组件布局显示之前执行,此时页面不可见(应用切换到前台不会触发)。
  • onShown:NavDestination组件布局显示之后执行,此时页面已完成布局。
  • onActive:NavDestination处于激活态(处于栈顶可操作,且上层无特殊组件遮挡)触发。
  • onWillHide:NavDestination组件触发隐藏之前执行(应用切换到后台不会触发)。
  • onInactive:NavDestination组件处于非激活态(处于非栈顶不可操作,或处于栈顶时上层有特殊组件遮挡)触发。
  • onHidden:NavDestination组件触发隐藏后执行(非栈顶页面push进栈,栈顶页面pop出栈或应用切换到后台)。
  • onWillDisappear:NavDestination组件即将销毁之前执行,如果有转场动画,会在动画前触发(栈顶页面pop出栈)。
  • onDisappear:通用生命周期事件,NavDestination组件从组件树上卸载销毁时执行。
  • aboutToDisappear:自定义组件析构销毁之前执行,不允许在该方法中改变状态变量。
@Component
struct PageOne {

  aboutToDisappear() {
  }

  aboutToAppear() {
  }
  
  build() {
    NavDestination() {
      // ...
    }
    .onWillAppear(() => {
    })
    .onAppear(() => {
    })
    .onWillShow(() => {
    })
    .onShown(() => {
    })
    .onWillHide(() => {
    })
    .onHidden(() => {
    })
    .onWillDisappear(() => {
    })
    .onDisAppear(() => {
    })
  }
}