文档管理中心
我的

router参数传递和接收示例

问题现象

在使用router进行页面路由跳转时,数据从页面一传输到页面二后,有以下常见问题:

  1. 无法获取参数。
  2. 参数里封装了函数,却无法调用。

背景知识

router通过pushUrl、replaceUrl、pushNamedRoute、replaceNamedRoute四种方式跳转并传递参数页面。

跳转方法的参数形式:

  • pushUrl与replaceUrl描述页面信息的参数为RouterOptions,传递参数结构形式为:
    {
      url: 'page/onePage', // 传递的方式,必填参数
      params: Object, // 传递的数据,必填参数
      recoverable: true // 页面是否可恢复,该参数为非必填参数,默认为true
    }
  • pushNamedRoute与replaceNamedRoute描述页面信息的参数为NamedRouterOptions,传递参数结构形式为:
    {
      name: 'Welcome', // 传递的方式,必填参数
      params: Object, // 传递的数据,必填参数
      recoverable: true // 页面是否可恢复,该参数为非必填参数,默认为true
    }
  • 注意事项:params不支持传递方法和系统返回的复杂对象。

获取参数的方式:getParams。获取的参数数据结构和传递的参数一致。

问题定位

对于跳转后调用方法失败的问题,需先确认params传递的数据类型是否合法,特别注意params参数不能传递方法和系统接口返回的复杂对象,仅能包含基础类型的数据;

若无法获取参数,可以按照以下步骤进行定位:

  1. 首先确定页面跳转时params参数是否为空或有效;
  2. 其次,确保正确获取params参数,接收params参数的变量类型与params类型必须一致。

分析结论

  • 当跳转传递的参数不为空时,考虑创建的params是否有效并检查params传递的类型情况。若params也没有问题,则考虑接收参数的问题;以pushUrl为例,参考以下形式:
    this.getUIContext().getRouter().pushUrl({
      url: 'pages/routerpage2',
      params: new routerParams('message', [123, 456, 789])
    })
  • router传递的参数会经过序列化,过程中会丢失方法。

修改建议

完整参数传递代码如下:

  • 页面一:
    // 定义公共参数类
    export class InfoTmp {
      age: number = 0;
    }
    
    export class ParamInfo {
      name: string = '';
      info: InfoTmp = new InfoTmp();
    }
    
    // 通过this.getUIContext().getRouter().pushUrl跳转至目标页携带params参数
    @Entry
    @Component
    struct Index {
      build() {
        Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
          Text('这是第一页')
            .fontSize(50)
            .fontWeight(FontWeight.Bold);
          Button() {
            Text('next page')
              .fontSize(25)
              .fontWeight(FontWeight.Bold)
              .margin(10);
          }
          .type(ButtonType.Capsule)
          .margin({ top: 20 })
          .backgroundColor('#F1F3F5')
          .onClick(() => {
            const params = new ParamInfo();
            params.name = 'Welcome';
            params.info.age = 20;
            this.getUIContext().getRouter().pushUrl({
              url: 'pages/Second',
              params: params
            });
          });
        }
        .width('100%')
        .height('100%');
      }
    }
  • 页面二:
    import { ParamInfo } from './Index';
    
    // 在second页面中接收传递过来的参数
    @Entry
    @Component
    struct Second {
      @State params: ParamInfo = this.getUIContext().getRouter().getParams() as ParamInfo;
    
      aboutToAppear(): void {
        // 方案一
        let params = (this.getUIContext().getRouter().getParams() as Record<string, object>);
        let name = params.name;
        let info = params.info;
        console.info(`Succeeded in completing PlanOne. params:{name: ${name}, info: ${info}}. `);
        // 方案二
        let paramInfo: ParamInfo = this.getUIContext().getRouter().getParams() as ParamInfo;
        console.info(`Succeeded in completing PlanTwo. params:{name: ${paramInfo.name}, info.age: ${paramInfo.info.age}}. `);
      }
    
      build() {
        Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
          Text(`第一页传来的数值:${this.params.name}`)
            .fontSize(20)
            .margin({ top: 20 })
            .backgroundColor(Color.Transparent);
        }
        .width('100%')
        .height('100%');
      }
    }

    页面二参数接收有以下两种方式,对比如下:

    展开

    方案

    优点

    缺点

    应用场景

    方案一:转成Record

    无需定义数据类

    遇到嵌套类型数据处理麻烦

    适用于只有基本类型场景

    方案二:转成特定的类

    嵌套类型数据处理简单

    需要事先定义好数据类

    适用于嵌套数据类型场景

常见FAQ

Q:params是否支持抽象类的传递?

A:不支持,复杂的页面传参建议使用Navigation。

Q:params传递HashMap类型数据,目标页面无法获取到内容如何解决?

A:router传递的参数会经过序列化,过程中会丢失方法。所以无法使用map,list传参。推荐使用Navigation。

Q:router路由跳转时params传入callback类型无效?

A:callback为回调函数方法,router的params参数不支持传递方法,因此无效。可以尝试使用EventHub实现类似的效果。

Q:params如何传递属性字符串、ArrayBuffer、PixelMap类型的数据?

A:router不支持传递函数和嵌套复杂结构类型的数据,可使用AppStorage或EventHub实现类似的效果。推荐使用Navigation。

Q:router获取的参数为什么无法清空?

A:router.getParams()获取的是路由记录中的只读参数副本,参数与页面实例绑定。每次onPageShow显示时都会读取同一份参数。需主动修改参数对象,每次跳转时强制传递新对象,参考代码如下:

this.getUIContext().getRouter().pushUrl({
  url: 'pages/Page',
  params: {} // 若不传递参数,传空对象,覆盖旧对象。
});

Q:如何使用router.back()返回上一个界面并传参?

A:RouterOptions中url设置为空字符,params传入传递的参数数据。