前言
页面跳转是移动应用最基础的能力之一。HarmonyOS 提供了@kit.ArkUI中的router模块来实现页面导航,其中router.pushUrl是最核心的跳转 API——它向页面栈中压入一个目标页,用户可以按返回键回到上一页。
本文以「猫猫大作战」中从主菜单跳转到排行榜详情页为场景,讲解router.pushUrl的路由规则、参数传递、返回栈管理、以及回调处理。同时为后续第 82 篇 Navigation 新路由体系埋下对比伏笔。
提示:本系列不讲 ArkTS 基础语法与环境搭建,假设你已跟完第 1–78 篇。本篇是阶段三第 79 篇。
一、router.pushUrl 基本用法
1.1 接口签名
import { router } from '@kit.ArkUI'; router.pushUrl(options: RouterOptions): Promise<void>; router.pushUrl(options: RouterOptions, callback: AsyncCallback<void>): void;1.2 RouterOptions 参数
interface RouterOptions { url: string; // 目标页面路径 params?: Object; // 传递的参数 modal?: boolean; // 是否模态(半透明背景) forResult?: boolean; // 是否需要返回结果(API 23+) recovery?: string; // 恢复策略(API 21+) }| 字段 | 必填 | 说明 |
|---|---|---|
url | ✅ | 目标页面路径,须在 main_pages.json 中注册 |
params | ❌ | 传递给目标页面的参数 |
modal | ❌ | 是否以模态方式打开(背景半透明) |
forResult | ❌ | 是否需要从目标页返回结果 |
recovery | ❌ | 应用恢复时的页面恢复策略 |
1.3 基础跳转示例
import { router } from '@kit.ArkUI'; import { BusinessError } from '@kit.BasicServicesKit'; @Entry @Component struct Index { build() { Column() { Button('🏆 查看排行榜') .onClick(() => { // 跳转到排行榜页面 router.pushUrl({ url: 'pages/Leaderboard', params: { fromPage: 'main_menu', highScore: this.highScore } }).catch((err: BusinessError) => { console.error(`跳转失败: ${err.message}`); }); }) } } }二、页面参数传递
2.1 发送方:通过 params 传参
// Index.ets — 传递参数 router.pushUrl({ url: 'pages/Leaderboard', params: { fromPage: 'main_menu', highScore: this.highScore, playerName: '猫猫侠', gameDate: '2026-07-24' } });2.2 接收方:router.getParams 取参
// Leaderboard.ets — 接收参数 @Entry @Component struct Leaderboard { @State fromPage: string = ''; @State highScore: number = 0; @State playerName: string = ''; @State gameDate: string = ''; aboutToAppear() { const params = router.getParams() as Record<string, Object>; this.fromPage = params?.['fromPage'] as string ?? ''; this.highScore = params?.['highScore'] as number ?? 0; this.playerName = params?.['playerName'] as string ?? ''; this.gameDate = params?.['gameDate'] as string ?? ''; } build() { Column() { Text(`来自: ${this.fromPage}`) Text(`最高分: ${this.highScore}`) Text(`玩家: ${this.playerName}`) Text(`日期: ${this.gameDate}`) } } }2.3 参数类型建议
| 参数类型 | 是否支持 | 示例 |
|---|---|---|
| string | ✅ | 'hello' |
| number | ✅ | 99999 |
| boolean | ✅ | true |
| Object | ✅ | { name: '猫猫侠', level: 5 } |
| Array | ✅ | [1, 2, 3] |
| Function | ❌ | 不支持序列化 |
| Class 实例 | ⚠️ | 建议序列化为 JSON |
注意:params 中的数据会被序列化传递,Function、Symbol、Date 等非序列化类型会被丢失。
三、页面返回栈管理
3.1 返回栈机制
初始状态:[Index] pushUrl('Leaderboard') → [Index, Leaderboard] ↑ 当前页 pushUrl('PlayerDetail') → [Index, Leaderboard, PlayerDetail] ↑ 当前页 按返回键 → [Index, Leaderboard] ↑ 当前页(Leaderboard.onPageShow 触发) 按返回键 → [Index] ↑ 当前页(Index.onPageShow 触发)3.2 router.back 返回
// Leaderboard.ets — 返回到 Index Button('返回') .onClick(() => { router.back(); // 弹出栈顶,回到上一个页面 })3.3 返回到指定页面
// 返回到指定路径的页面(跳过多层) router.back({ url: 'pages/Index' });3.4 带结果返回(API 23+)
// Index.ets — 跳转时标记 forResult router.pushUrl({ url: 'pages/Leaderboard', params: { fromPage: 'main_menu' }, forResult: true }); // Leaderboard.ets — 返回时带数据 Button('选择并返回') .onClick(() => { router.back({ url: 'pages/Index', params: { selectedScore: 88888, selectedPlayer: '猫猫侠' } }); })四、模态跳转
4.1 模态页面
// 以模态方式打开设置页面(半透明背景) router.pushUrl({ url: 'pages/Settings', modal: true });模态页面的特点:
| 特性 | 普通跳转 | 模态跳转 |
|---|---|---|
| 背景 | 完全替换 | 保留上一页背景(半透明) |
| 返回方式 | 返回键/back() | 返回键/back() |
| 动画 | 页面堆叠 | 底部弹出式动画 |
| 适用场景 | 普通页面跳转 | 设置、弹窗、选项 |
五、错误处理
5.1 常见错误码
router.pushUrl({ url: 'pages/Leaderboard' }) .catch((err: BusinessError) => { switch (err.code) { case 100001: console.error('页面不存在(未在 main_pages.json 中注册)'); break; case 100002: console.error('页面栈已满'); break; case 100003: console.error('跳转被拦截'); break; default: console.error(`未知错误: ${err.code} ${err.message}`); } });| 错误码 | 含义 | 解决方案 |
|---|---|---|
| 100001 | 目标页面不存在 | 检查 main_pages.json 注册 |
| 100002 | 页面栈超限 | 使用 replaceUrl 或清理栈 |
| 100003 | 路由被拦截 | 检查是否设置了路由拦截 |
| 其他 | 系统错误 | 捕获异常并重试 |
5.2 防止重复跳转
// 使用标志位防止按钮连点导致的重复跳转 @State navigating: boolean = false; goToLeaderboard() { if (this.navigating) return; this.navigating = true; router.pushUrl({ url: 'pages/Leaderboard' }) .then(() => { this.navigating = false; }) .catch(() => { this.navigating = false; }); }六、router.pushUrl 与生命周期
6.1 跳转时的生命周期时序
跳转前:Index(当前页面) ↓ router.pushUrl('pages/Leaderboard') ↓ Leaderboard.aboutToAppear() ← 目标页准备 Index.onPageHide() ← 原页隐藏 Leaderboard.build() ← 目标页渲染 Leaderboard.onDidBuild() ← 目标页渲染完成 Leaderboard.onPageShow() ← 目标页可见 ↓ 用户看到 Leaderboard 页面6.2 返回时的生命周期时序
返回前:Leaderboard(当前页面) ↓ router.back() ↓ Leaderboard.aboutToDisappear() ← 目标页销毁 Index.onPageShow() ← 原页重新可见 Leaderboard 组件销毁 ← 从页面栈移除七、router.pushUrl vs Navigation.pushPath
| 对比维度 | router.pushUrl | Navigation.pushPath |
|---|---|---|
| 引入方式 | import { router } from '@kit.ArkUI' | NavPathStack 实例方法 |
| 页面注册 | main_pages.json | 需 + navDestination @Builder 注册 |
| 参数类型 | params: Object | param: Object |
| 返回结果 | forResult参数 | 原生支持结果回调 |
| 拦截能力 | 无 | setInterception支持 |
| 分栏模式 | 不支持 | 支持 Split 分栏 |
| 官方推荐 | 旧方案 | 推荐方案(新) |
从 API 12 开始,官方推荐使用 Navigation 方案。但理解 router 是理解 Navigation 的基础,且老项目可能仍在大量使用 router。
八、常见踩坑
8.1 坑一:路径前没有加 pages/
// 🚫 错误:路径不完整 router.pushUrl({ url: 'Leaderboard' }); // ✅ 正确:完整路径 router.pushUrl({ url: 'pages/Leaderboard' });8.2 坑二:页面栈溢出
// 🚫 连续 pushUrl 导致页面栈溢出 for (let i = 0; i < 100; i++) { router.pushUrl({ url: 'pages/Detail' }); } // 页面栈默认容量约 32 层,超出会报错 100002九、总结
router.pushUrl是 HarmonyOS 经典的路由跳转 API,通过 URL 路径 + params 参数实现页面间导航和通信。虽然官方已推荐使用 Navigation 替代,但理解 router 的页面栈管理、生命周期时序和参数传递机制,仍然是掌握 HarmonyOS 路由体系的基础。
核心要点:
pushUrl向页面栈压入新页面,back()弹出页面params传递页面参数,接收方通过router.getParams()获取- 路径必须与
main_pages.json注册一致,不含.ets扩展 - 模态跳转(
modal: true)支持半透明背景 - 推荐用
forResult实现返回结果传递(API 23+) - 注意防重复跳转和页面栈溢出
下一篇预告:第 80 篇将深入router.replaceUrl— 无回退栈的页面替换导航。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- router API 官方参考
- 页面路由与生命周期
- router 到 Navigation 迁移
- BusinessError 错误码参考
- Navigation 新路由架构
- 开源鸿蒙跨平台社区
- 第 78 篇:main_pages 路由表
- 第 80 篇:router.replaceUrl 替换导航