一、页面结构

1.1 Router页面结构

Router路由的页面是一个@Entry修饰的Component,每一个页面都需要在main_page.json中声明。

// main_page.json
{
  "src": [
    "pages/Index",
    "pages/pageOne",
    "pages/pageTwo"
  ]
}
// Router页面示例
@Entry
@Component
struct Index {
  build() {
    Button('router to pageOne')
      .onClick(() => {
        this.getUIContext().getRouter().pushUrl({
          url: 'pages/pageOne'
        });
      })
  }
}

1.2 Navigation页面结构

Navigation的路由页面分为导航页(Navbar)子页(NavDestination)

  • 导航页(Navbar):Navigation包含的子组件

  • 子页(NavDestination):NavDestination包含的子组件

// Navigation导航页示例
@Entry
@Component
struct Index {
  pathStack: NavPathStack = new NavPathStack();
  
  build() {
    Navigation(this.pathStack) {
      Button('Push PageOne')
        .onClick(() => {
          this.pathStack.pushPathByName('navigation_pageOne', null);
        })
    }
    .title('Navigation')
  }
}
// Navigation子页示例
@Builder
export function PageOneBuilder() {
  PageOne();
}

@Component
export struct PageOne {
  pathStack: NavPathStack = new NavPathStack();
  
  build() {
    NavDestination() {
      Button('回到首页')
        .onClick(() => {
          this.pathStack.clear();
        })
    }
    .title('PageOne')
    .onReady((context: NavDestinationContext) => {
      this.pathStack = context.pathStack;
    })
  }
}

注意:每个子页面也需要配置到系统配置文件router_map.json中(参考系统路由表)。

二、路由操作

2.1 Router路由操作

Router通过@ohos.router模块提供的方法来操作页面,建议使用UIContext中的getRouter获取Router对象。

// push page
this.getUIContext().getRouter().pushUrl({ url: 'pages/pageOne', params: null });

// pop page
this.getUIContext().getRouter().back({ url: 'pages/pageOne' });

// replace page
this.getUIContext().getRouter().replaceUrl({ url: 'pages/pageOne' });

// clear all page
this.getUIContext().getRouter().clear();

// 获取页面栈大小
let size = this.getUIContext().getRouter().getLength();

// 获取页面状态
let pageState = this.getUIContext().getRouter().getState();

2.2 Navigation路由操作

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

@Entry
@Component
struct Index {
  pathStack: NavPathStack = new NavPathStack();
  
  build() {
    Navigation(this.pathStack) {
      // 导航内容
    }
  }
}

// push page
this.pathStack.pushPath({ name: 'pageOne' });

// pop page
this.pathStack.pop();
this.pathStack.popToIndex(1);
this.pathStack.popToName('pageOne');

// replace page
this.pathStack.replacePath({ name: 'pageOne' });

// clear all page
this.pathStack.clear();

// 获取路由栈大小
let size: number = this.pathStack.size();

// 删除栈中name为PageOne的所有页面
this.pathStack.removeByName('pageOne');

// 删除指定索引的页面
this.pathStack.removeByIndexes([1, 3, 5]);

// 获取栈中所有页面name集合
this.pathStack.getAllPathName();

// 获取索引为1的页面参数
this.pathStack.getParamByIndex(1);

// 获取PageOne页面的参数
this.pathStack.getParamByName('pageOne');

// 获取PageOne页面的索引集合
this.pathStack.getIndexByName('pageOne');

2.3 获取NavPathStack的几种方式

Navigation子页面想要做路由需要拿到Navigation持有的导航控制器对象NavPathStack:

方式 说明 推荐度
方式一:@Provide/@Consume 有耦合,不推荐 ⭐⭐
方式二:onReady回调 推荐 ⭐⭐⭐⭐⭐
方式三:AppStorage全局设置 推荐 ⭐⭐⭐⭐
方式四:queryNavigationInfo 推荐 ⭐⭐⭐⭐

方式二:通过OnReady回调获取(推荐)

@Component
export struct PageOne {
  pathStack: NavPathStack = new NavPathStack();
  
  build() {
    NavDestination() {
      // 页面内容
    }
    .onReady((context: NavDestinationContext) => {
      this.pathStack = context.pathStack;
    })
  }
}

方式三:通过AppStorage全局设置

@Entry
@Component
struct Index {
  pathStack: NavPathStack = new NavPathStack();
  
  aboutToAppear(): void {
    AppStorage.setOrCreate('PathStack', this.pathStack);
  }
  
  build() {
    Navigation(this.pathStack) { }
  }
}

// 子页面获取
pathStack: NavPathStack = AppStorage.get('PathStack') as NavPathStack;

方式四:通过queryNavigationInfo查询

@Component
struct CustomNode {
  pathStack: NavPathStack = new NavPathStack();
  
  aboutToAppear() {
    let navigationInfo: NavigationInfo = this.queryNavigationInfo() as NavigationInfo;
    if (navigationInfo != undefined) {
      this.pathStack = navigationInfo.pathStack;
    }
  }
}

三、生命周期

3.1 Router页面生命周期

Router页面生命周期为@Entry页面中的通用方法:

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

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

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

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

3.2 Navigation页面生命周期

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

@Entry
@Component
struct PageOne {
  build() {
    NavDestination() {
      // 页面内容
    }
    .onWillAppear(() => { })      // 页面即将显示
    .onAppear(() => { })          // 页面显示
    .onWillShow(() => { })        // 页面即将展示
    .onShown(() => { })           // 页面已展示
    .onWillHide(() => { })        // 页面即将隐藏
    .onHidden(() => { })          // 页面已隐藏
    .onWillDisappear(() => { })   // 页面即将销毁
    .onDisAppear(() => { })       // 页面已销毁
  }
}

3.3 生命周期关系说明

规则 说明
Router影响Navigation Router页面的跳转会影响其内部Navigation页面的生命周期
Navigation不影响Router Navigation页面的跳转不会影响其所在router页面的生命周期
前后台共同触发 应用前后台切换会同时触发router页面和Navigation页面的生命周期

四、转场动画

对比项 Router Navigation
转场动画 支持 支持
自定义转场 pageTransition()通用方法 customNavContentTransition事件
Dialog类型页面 - API 13前无动画,13后支持系统转场

五、共享元素转场

对比项 Router Navigation
共享元素转场 sharedTransition通用属性 geometryTransition属性(NavDestination之间切换)

六、跨包路由

6.1 Router跨包路由

Router通过命名路由的方式实现跨包跳转。

// 共享包中定义
@Entry({ routeName: 'myPage' })
@Component
export struct MyComponent { }

// 跳转页面
import('library/src/main/ets/pages/Index');
this.getUIContext().getRouter().pushNamedRoute({
  name: 'myPage',
  params: { data1: 'message' }
});

6.2 Navigation跨包路由

Navigation作为路由组件,默认支持跨包跳转

// 1. 导入跨包的路由页面
import { PageInHSP } from 'library';

@Entry
@Component
struct mainPage {
  pageStack: NavPathStack = new NavPathStack();
  
  @Builder pageMap(name: string) {
    if (name === 'PageInHSP') {
      PageInHSP();  // 2. 定义路由映射表
    }
  }
  
  build() {
    Navigation(this.pageStack) {
      Button('Push HSP Page')
        .onClick(() => {
          this.pageStack.pushPath({ name: 'PageInHSP' });  // 3. 跳转
        })
    }
    .navDestination(this.pageMap)
  }
}

七、动态路由

7.1 动态路由的优势

优势 说明
配置丰富 可配置横竖屏默认模式、是否需要鉴权等扩展信息
按名称跳转 按照名称进行跳转而不是ets文件路径
按需加载 使用动态Import,防止首个页面加载大量代码

7.2 Navigation动态路由实现方案

方案 说明 起始版本
自定义路由表 开发自定义路由管理模块,通过WrappedBuilder封装 -
系统路由表 系统管理路由表,各模块独立配置router_map.json API 12

八、生命周期监听

框架 监听方式
Router uiObserver.on('routerPageUpdate')
Navigation UIObserver.on('navDestinationUpdate')
// Navigation生命周期监听示例
let uiObserver: UIObserver = uiContext.getUIObserver();
uiObserver.on('navDestinationUpdate', (info) => {
  // NavDestinationState.ON_SHOWN = 0, ON_HIDE = 1
  if (info.state == 0) {
    hilog.info(TAG, 'page ON_SHOWN:' + info.name.toString())
  }
})

九、页面信息查询

框架 查询接口 返回值
Router queryRouterPageInfo() RouterPageInfo(包含context、index、name、path、state、pageId)
Navigation queryNavDestinationInfo() NavDestinationInfo(包含navigationId、name、state、index、param、navDestinationId)

十、路由拦截

框架 路由拦截能力
Router 不支持,需自行封装
Navigation 支持setInterception方法设置页面跳转拦截回调

核心对比

对比项 Router Navigation
页面结构 @Entry组件 Navbar + NavDestination
路由栈操作 router对象方法 NavPathStack方法
生命周期 aboutToAppear等 NavDestination事件
跨包路由 命名路由 默认支持
动态路由 自定义 自定义/系统路由表
路由拦截 不支持 setInterception

迁移推荐

场景 推荐方案
获取路由栈 onReady回调
跨包路由 系统路由表
动态路由 系统路由表(API 12+)
路由拦截 setInterception
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐