HarmonyOS鸿蒙Next中Router页面复杂对象如何传参

HarmonyOS鸿蒙Next中Router页面复杂对象如何传参 使用Router进行页面跳转传参时,数组、自定义实体类等对象如何传参给二级页面?

11 回复

尊敬的开发者,您好,
使用 Router 进行页面跳转传参时,对于数组、自定义实体类等复杂对象,推荐通过JSON 序列化的方式传递
可以参考:基于router实现页面跳转功能
示例代码:

//一级页面pages/IndexPage.ets
import { router } from '@kit.ArkUI';

// 自定义实体类
class UserInfo {
  name: string = '';
  age: number = 0;
  tags: string[] = [];
}

@Entry
@Component
struct IndexPage {
  build() {
    Button('跳转并传参')
      .onClick(() => {
        // 构造复杂对象
        let user: UserInfo = {
          name: '张三',
          age: 25,
          tags: ['开发者', '鸿蒙']
        };

        // 序列化后传递
        router.pushUrl({
          url: 'pages/SecondPage',
          params: {
            userData: JSON.stringify(user),
            source: 'IndexPage'
          }
        });
      });
  }
}




//二级页面pages/SecondPage.ets
import { router } from '@kit.ArkUI';
class UserInfo {
  name: string = '';
  age: number = 0;
  tags: string[] = [];
}
@Entry
@Component
struct SecondPage {
  @State userName: string = '';
  @State userAge: number = 0;
  @State userTags: string[] = [];

  aboutToAppear() {
    // 获取参数并反序列化
    const params = router.getParams() as Record<string, Object>;
    if (params) {
      try {
        const userDataStr = params['userData'] as string;
        const userData:UserInfo = JSON.parse(userDataStr);
        this.userName = userData.name;
        this.userAge = userData.age;
        this.userTags = userData.tags;
      } catch (error) {
        console.error('参数解析失败', error);
      }
    }
  }

  build() {
    Column() {
      Text(`姓名:${this.userName}`)
      Text(`年龄:${this.userAge}`)
      ForEach(this.userTags, (tag: string) => {
        Text(`标签:${tag}`)
      })
    }
  }
}

问题解决方案:

请按照如下流程进行操作:

该问题可以参考的文档如下:

合作愉快。
华为开发者联盟

更多关于HarmonyOS鸿蒙Next中Router页面复杂对象如何传参的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


可以传,但建议传 纯数据对象 DTO,不要直接依赖实体类里的方法。Router 参数本质适合传可序列化数据:stringnumberboolean、数组、普通对象。自定义类可以传字段,但对象里的方法不要传,二级页面需要方法时重新组装实体类。

示例代码:

一级页面:pages/Index.ets

import router from '@ohos.router';

class GoodsDto {
  id: string = '';
  name: string = '';
  price: number = 0;

  constructor(id: string, name: string, price: number) {
    this.id = id;
    this.name = name;
    this.price = price;
  }
}

class DetailParams {
  title: string = '';
  goodsList: GoodsDto[] = [];
  selectedGoods: GoodsDto = new GoodsDto('', '', 0);
}

@Entry
@Component
struct Index {
  private goodsList: GoodsDto[] = [
    new GoodsDto('1001', '手机', 3999),
    new GoodsDto('1002', '耳机', 699)
  ];

  private jumpToDetail(): void {
    let params = new DetailParams();
    params.title = '商品详情';
    params.goodsList = this.goodsList;
    params.selectedGoods = this.goodsList[0];

    router.pushUrl({
      url: 'pages/Detail',
      params: params
    });
  }

  build() {
    Column() {
      Button('跳转详情页')
        .onClick(() => {
          this.jumpToDetail();
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

二级页面:pages/Detail.ets

import router from '@ohos.router';

class GoodsDto {
  id: string = '';
  name: string = '';
  price: number = 0;
}

class DetailParams {
  title: string = '';
  goodsList: GoodsDto[] = [];
  selectedGoods: GoodsDto = new GoodsDto();
}

@Entry
@Component
struct Detail {
  @State title: string = '';
  @State goodsName: string = '';
  @State count: number = 0;

  aboutToAppear(): void {
    let params = router.getParams() as DetailParams;

    this.title = params.title;
    this.goodsName = params.selectedGoods.name;
    this.count = params.goodsList.length;
  }

  build() {
    Column({ space: 12 }) {
      Text(this.title)
        .fontSize(20)

      Text(`选中商品:${this.goodsName}`)
        .fontSize(16)

      Text(`商品数量:${this.count}`)
        .fontSize(16)

      Button('返回')
        .onClick(() => {
          router.back();
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

注意点:

// 不建议传带方法的实体类
class Goods {
  id: string = '';
  name: string = '';

  getDisplayName(): string {
    return this.name;
  }
}

如果二级页面需要 getDisplayName() 这类方法,建议只传 DTO 数据,到二级页面后重新构造业务实体。

大对象、图片二进制、超大数组不要直接走 Router 参数。更稳的做法是传 id,详情页再从缓存、数据库、AppStorage 或接口里取完整数据。

学习了

在 ArkUI 开发里 router 传参本身不适合直接传复杂对象。

Router 参数主要支持基础类型:

string
number
boolean

如果直接传:

router.pushUrl({
  url: 'pages/detail',
  params: {
    list: myArray
  }
})

数组、自定义对象可能会出现:

  • 数据丢失
  • 类型变成普通 Object
  • 序列化异常

一般有几种处理方式:

方式1:JSON序列化(简单场景推荐)

跳转:

const data = {
  id: 1,
  name: 'test',
  list: [1, 2, 3]
}

router.pushUrl({
  url: 'pages/detail',
  params: {
    data: JSON.stringify(data)
  }
})

目标页面:

const params = router.getParams()

const data = JSON.parse(params.data as string)

适合:

  • 列表
  • 详情数据
  • 普通实体对象

方式2:只传id,二级页面重新查询(更推荐)

比如商品详情:

不要传整个商品:

{
  id: 100,
  name: 'xxx',
  price: 99
}

直接:

router.pushUrl({
  url: 'pages/detail',
  params: {
    id: 100
  }
})

详情页:

根据 id:

  • 数据库查询
  • 或者请求接口

这个更符合实际项目。

方式3:使用 AppStorage / 状态管理共享

如果是页面间共享复杂数据:

比如:

  • 用户信息
  • 购物车
  • 编辑状态

可以:

AppStorage.setOrCreate('userInfo', user)

目标页面:

const user = AppStorage.get('userInfo')

简单总结:

  • 小数据:JSON.stringify + JSON.parse
  • 大对象:传 id,目标页面重新获取
  • 全局状态:AppStorage / 状态管理

不要直接通过 Router 传复杂对象,后面维护容易踩坑。

希望可以帮到你~~~

期待HarmonyOS能在未来推出更多针对企业用户的解决方案。

先说方案:序列化

其实大部分开发语言都是通用的,需要通过 Router 进行页面跳转传参时,对于数组、自定义实体类等复杂对象,肯定是不能直接传递,都必须要先进行序列化(通常使用 JSON.stringify),然后在目标页面接收时再反序列化(使用 JSON.parse

router跳转的方式已过时,建议使用Navigation 方式跳转

Router方式传参的话,params不支持传递复杂对象。它是值复制传递。所以需经过序列化。
对于数组、自定义实体类对象,也只是复制值,不是传递引用。
可以看下 router参数传递和接收示例
如果传递复杂对象可以考虑Appstorage。几种传递方式参考:

方案 支持传递类型 是否保留方法 适用场景
Navigation + NavPathStack 自定义对象、基本类型 官方推荐,新项目首选
Router + DTO 纯数据 可序列化 JSON 数据 简单场景,已有 Router 项目
Router + JSON 序列化 可序列化 JSON 数据 嵌套较深的数据结构
AppStorage / EventHub 任意类型(含类实例、函数) 需要传递含方法的对象或回调

可以直接通过 RouterOptions.params 传参。SDK 里 params 类型就是 Object,所以数组、普通对象都可以放进去;目标页再通过 getParams() 取出即可。建议尽量传“可序列化的普通数据”,自定义 class 实例不要依赖方法或原型在页面间保留,必要时在目标页按字段重新组装实例。

示例:

// 跳转页
interface UserInfo {
  id: number
  name: string
}

const users: UserInfo[] = [
  { id: 1, name: 'Tom' },
  { id: 2, name: 'Jerry' }
]

this.getUIContext().getRouter().pushUrl({
  url: 'pages/SecondPage',
  params: {
    users,
    extra: { from: 'home' }
  }
})

// 目标页
aboutToAppear() {
  const params = this.getUIContext().getRouter().getParams() as Record<string, Object>
  const users = params['users'] as UserInfo[]
  const extra = params['extra'] as Record<string, string>
}

如果你用的是老写法,也可以 import router from ‘@ohos.router’ 后使用 router.pushUrl({ url, params }) / router.getParams();不过较新的 API 中更推荐通过 UIContext 获取 Router。

注意两点:

  1. params 适合传页面初始化所需的小数据,不建议塞很大的列表、图片二进制、文件内容等。
  2. 如果对象很复杂或需要跨多个页面共享/修改,建议只传 id 或 key,真实数据放到 AppStorage、LocalStorage、全局状态管理或业务单例中,目标页按 key 再取。

HarmonyOS NEXT 使用 Navigation 路由,通过 NavPathStack.pushPath({ params: object }) 传递复杂对象。接收页在 aboutToAppear 中通过 this.params 获取。对象需为普通类或 @Observed 类,无需序列化。不建议使用已废弃的 Router 模块。,

在HarmonyOS Next中,router.pushUrlparams 字段支持基础类型(如string、number)以及JSON可序列化对象。对于数组或自定义实体类,需遵守以下规则:

  • 自定义实体类必须实现 serializedeserialize 方法,或直接使用 JSON.stringify 序列化为字符串传递,接收方再解析。
  • 数组可直接传递,但需保证内部元素为可序列化类型,或整体序列化为字符串。

示例代码:

// 发送页
import { router } from '@kit.ArkUI';

class User {
  name: string;
  age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

function send() {
  let user = new User('Alice', 25);
  let arr = [1, 2, 3];
  router.pushUrl({
    url: 'pages/Second',
    params: {
      user: JSON.stringify(user), // 序列化为字符串
      arr: arr // 数组直接传
    }
  });
}

// 接收页
import { router } from '@kit.ArkUI';
import { JSON } from '@kit.ArkTS';

function receive() {
  const params = router.getParams() as Record<string, Object>;
  const userStr = params['user'] as string;
  const user = JSON.parse(userStr) as User;
  const arr = params['arr'] as number[];
}

注意:自定义实体类若直接作为 params 传递,需要实现 serialize/deserialize 方法,否则无法通过类型校验。推荐使用 JSON.stringify 处理自定义对象,简单可靠。数组若包含自定义对象,同样建议整体序列化。

回到顶部