小程序有哪些页面跳转方式?它们有什么区别?
简化版
小程序常见跳转方式有 navigateTo、redirectTo、switchTab、reLaunch、navigateBack。核心区别在于是否保留当前页面、是否能跳 tabBar 页面、是否清空页面栈。理解页面栈是回答这类问题的关键。
详细版
常见 API:
navigateTo:保留当前页面,跳到非 tabBar 页面。redirectTo:关闭当前页面,跳到非 tabBar 页面。switchTab:跳到 tabBar 页面,并关闭其他非 tabBar 页面。reLaunch:关闭所有页面,打开指定页面。navigateBack:返回上一页或多级页面。
页面栈决定了返回行为。navigateTo 会增加页面栈层级,所以可以返回;redirectTo 替换当前页,不能返回被替换页面;reLaunch 清空栈,适合登录后进入首页或退出后回登录页。
完整版教学
一、页面栈是什么
小程序维护一个页面栈,用户每打开一个新页面,就可能往栈里压入一个页面。返回时从栈顶弹出当前页面,露出上一个页面。
理解页面栈后,跳转 API 就不难了。它们本质上是在控制页面栈怎么变化。
二、常见跳转 API 对比
navigateTo 是最常用的普通跳转方式。它会保留当前页面,再打开新页面。适合从列表进入详情,因为用户通常需要返回列表。
redirectTo 会关闭当前页面,再打开新页面。适合流程页替换,比如提交成功页不希望用户返回提交表单。
switchTab 专门用于跳转 tabBar 页面。普通跳转 API 不能直接跳 tabBar 页面。
reLaunch 会清空所有页面并打开新页面。适合重置应用状态,比如退出登录后进入登录页。
navigateBack 用来返回,支持通过 delta 指定返回层级。
三、常见错误
很多问题来自混用跳转 API:
- 用
navigateTo跳 tabBar 页面会失败。 - 用
redirectTo后发现返回不了上一页,这是正常的,因为当前页被替换了。 - 流程页一直
navigateTo,导致页面栈越来越深。 - 登录态失效时只
navigateBack,可能回到不该访问的页面。
四、面试追问与工程落地
面试官可能问:“登录成功后应该用什么跳转?”
如果登录页不希望用户返回,通常用 redirectTo 或 reLaunch。如果要进入 tabBar 首页,则使用 switchTab 或 reLaunch。如果要清理历史页面,优先 reLaunch。
工程中可以封装统一路由方法,把登录校验、参数序列化、异常提示、tabBar 判断集中处理,减少页面中散落大量 wx.navigateTo。
五、用页面栈推演 API
用 A、B、C 三个页面推演最直观:A navigateTo B 后栈为 [A, B],B 再打开 C 为 [A, B, C];C navigateBack({ delta: 2 }) 后回到 A。若 B 使用 redirectTo C,则 [A, B] 变为 [A, C],B 已卸载,无法再返回。
| API | 栈变化示例 | tabBar 目标 | 典型场景 |
|---|---|---|---|
navigateTo | [A] → [A,B] | 不可 | 列表进入详情 |
redirectTo | [A,B] → [A,C] | 不可 | 流程当前步骤替换 |
navigateBack | [A,B,C] → [A] | 不涉及 | 返回一层或多层 |
switchTab | 切到指定 tab,关闭其他非 tab 页 | 必须 | 进入主导航页 |
reLaunch | [...] → [T] | 可 | 登录失效、全局重置 |
小程序页面栈存在层数上限,常见文档口径是最多 10 层;连续 navigateTo 的流程应在接近上限前改用替换、返回或重构导航。不要把这个限制当业务分页计数,而要从交互上避免用户钻进无法理解的深栈。
六、参数、返回通信与状态恢复
URL 查询参数适合小而稳定的标识,例如经过编码的 id=42,不适合塞完整 JSON、敏感信息或权威价格。目标页在 onLoad(options) 读取参数后仍要请求或校验最新数据,因为路由参数可被构造,也可能在页面驻留期间过期。
navigateTo 可通过 events 与成功回调中的 eventChannel 在打开页和被打开页之间传递一次性结果。例如选择地址页返回 { addressId: 7 },原页面收到后重新查询地址;这比获取 getCurrentPages() 后直接修改上一页实例更清晰。
wx.navigateTo({
url: '/pages/address/select',
events: {
selected({ addressId }) {
reloadAddress(addressId)
}
}
})
// 选择页:this.getOpenerEventChannel().emit('selected', { addressId: 7 })
跨页面长期共享状态再使用 store 或服务端,不要让 EventChannel 变成全局总线。
tabBar 页面可能已经存在,switchTab 后通常触发其 onShow 而不是重新 onLoad。路由封装应处理 tabBar 白名单、参数编码、失败回调和登录重定向,并防止登录页自身再次触发登录重定向形成循环。
记忆钩子:先画栈再选 API——要“压栈返回”用 navigate,要“替换当前”用 redirect,要“清空重来”用 reLaunch。
七、常见误区与追问
- 误区:
navigateTo可以打开任意页面,包括 tabBar 页面。 tabBar 页面应使用switchTab,普通压栈 API 不适用。 - 误区:
redirectTo会清空整个页面栈。 它只替换当前页;清空并建立新根页面的是reLaunch。 - 误区:页面参数来自自己代码,所以服务端可以直接信任。 路径可以被分享或构造,身份、金额和资源权限仍要由服务端校验。
- 追问:登录成功后选
redirectTo还是reLaunch? 只替换登录页可用 redirect;需要清除所有受保护历史页时用 reLaunch;目标是 tabBar 且无需清栈可 switchTab。 - 追问:详情页返回列表如何带回刷新结果? 可用 EventChannel 返回最小结果,或让列表在
onShow按脏标记重新请求。 - 追问:为什么不建议直接修改
getCurrentPages()中上一页的数据? 它耦合页面实现和栈结构,绕过明确通信契约,重构与异常路由时容易失效。 - 追问:如何避免页面栈过深? 流程完成后 redirect/reLaunch,能返回已有页时 navigateBack,并在统一路由层监控栈深。
八、加强记忆
路由 API 不靠死背,画页面栈即可:navigateTo 压栈并保留返回,redirectTo 替换栈顶,navigateBack 弹栈,switchTab 进入 tabBar,reLaunch 清栈重建。参数只传最小标识,返回结果用 EventChannel 或可见时刷新;业务权威状态由服务端维护,并始终防止深栈和重定向循环。