一、uni-app 路由跳转方式汇总
| 跳转方式 (API) | 当前页面处理 | 页面栈变化 | 能否传参 | 典型实际开发场景 |
|---|---|---|---|---|
| uni.navigateTo | 保留(不销毁,压入栈中) | 叠加(+1) | 能(URL拼接) | 列表页跳转到详情页(最常用) |
| uni.redirectTo | 关闭(销毁当前页面) | 替换(±0) | 能(URL拼接) | 登录成功跳首页、表单提交成功跳结果页 |
| uni.reLaunch | 全关(销毁所有历史页面) | 清空重置 | 能(URL拼接) | 退出登录、切换账号、应用强制重置 |
| uni.switchTab | 关闭(销毁所有非 Tab 页面) | 重置为 Tab 页 | 不能(不支持 URL 传参) | 底部 Tab 栏切换、业务流程结束回主页 |
| uni.navigateBack | 关闭(销毁当前页面) | 回退(-N) | 不能(需间接传值) | 自定义返回按钮、跨级返回上一页 |
二、navigateTo
作用
保留当前页面,跳转到应用内的某个非 tabBar 页面。跳转后,新页面会压入页面栈,用户可以通过左上角的返回按钮或调用 uni.navigateBack 回到原页面。
2. 用法
基础跳转:
javascript
uni.navigateTo({
url: '/pages/detail/detail?id=123&name=test'
});
目标页面接收参数(Vue3 setup 语法糖):
vue
<script setup>
import { onLoad } from '@dcloudio/uni-app';
onLoad((options) => {
console.log(options.id); // 123
console.log(options.name); // test
});
</script>
页面间通信(events 事件监听,2.8.9+ 支持):
javascript
// 发起跳转的页面
uni.navigateTo({
url: '/pages/detail/detail',
events: {
// 监听目标页面传回的数据
acceptDataFromOpenedPage: function(data) {
console.log(data);
}
},
success: function(res) {
// 向目标页面发送数据
res.eventChannel.emit('acceptDataFromOpenerPage', { data: '来自上一页' });
}
});
3. 避坑指南
页面栈溢出(10层限制)
- 现象 :连续跳转超过 10 次后,报错
navigateTo:fail:page limit exceeded:10或静默失败。 - 原因:uni-app 限制页面栈最大深度为 10 层。
- 解决 :跳转前通过
getCurrentPages()检查栈深度,若接近 10 层,改用uni.redirectTo替换当前页面,或uni.navigateBack释放栈空间后再跳转。
无法跳转 TabBar 页面
- 现象:使用 navigateTo 跳转底部导航栏页面时,页面没有反应或报错。
- 解决 :跳转 TabBar 页面必须使用
uni.switchTab。
URL 参数长度限制与乱码
- 现象:传递复杂的 JSON 对象或超长字符串时,参数丢失或接收端乱码。
- 解决 :URL 有长度限制,复杂数据应改用全局状态管理(如 Pinia)或本地缓存(
uni.setStorageSync);若必须通过 URL 传递特殊字符,发送端需使用encodeURIComponent编码,接收端使用decodeURIComponent解码。
H5 端微信浏览器兼容问题
- 现象:在微信公众号 H5 中,使用 navigateTo 跳转后,调用微信 JSSDK(如获取定位)在 iOS 上签名校验失败。
- 原因:iOS 微信浏览器在 navigateTo 跳转后,获取的当前页面链接可能仍是列表页链接,导致签名比对失败。
- 解决:涉及 JSSDK 签名的页面,尽量避免深层 navigateTo,或在 iOS 端做特殊的路由刷新处理。
三、redirectTo
作用
关闭当前页面,跳转到应用内的某个非 tabBar 页面。新页面会替换当前页面在页面栈中的位置,用户无法通过返回按钮回到被关闭的当前页面。
2. 用法
基础跳转:
javascript
uni.redirectTo({
url: '/pages/result/result?status=success'
});
目标页面接收参数(Vue3 setup):
vue
<script setup>
import { onLoad } from '@dcloudio/uni-app';
onLoad((options) => {
console.log(options.status); // success
});
</script>
3. 避坑指南
坑点一:无法跳转 TabBar 页面
- 现象:跳转底部导航栏页面时静默失败或报错。
- 解决 :跳转 TabBar 页面必须使用
uni.switchTab。
坑点二:误用导致用户无法回退
- 现象:用户在详情页点击返回按钮,直接退出了小程序或回到了很远的页面。
- 原因:redirectTo 会销毁当前页面,如果用在列表页跳详情页的场景,用户看完详情就无法回到列表了。
- 解决:严格区分场景,只有"不需要返回当前页"(如登录成功、表单提交成功)时才使用 redirectTo。
坑点三:页面栈深度不增加
- 现象 :连续使用 redirectTo 跳转多次后,调用
uni.navigateBack发现回退的层级不对。 - 原因:redirectTo 是替换操作(±0),不会增加页面栈深度。
- 解决 :需要精确控制返回层级时,使用
getCurrentPages()动态计算 delta 值。
四、reLaunch
作用
关闭所有已打开的页面,打开到应用内的某个页面。相当于对应用的导航状态进行了一次"硬重启",目标页面成为新的页面栈根页面。
2. 用法
基础跳转:
javascript
uni.reLaunch({
url: '/pages/index/index'
});
带参数跳转(非 TabBar 页面):
javascript
uni.reLaunch({
url: '/pages/detail/detail?id=123&_t=' + Date.now()
});
目标页面接收参数(Vue3 setup):
vue
<script setup>
import { onLoad } from '@dcloudio/uni-app';
onLoad((options) => {
console.log(options.id); // 123
});
</script>
3. 避坑指南
坑点一:TabBar 页面不能带参数
- 现象 :跳转 TabBar 页面时 URL 带了
?key=value,参数被忽略或跳转静默失败。 - 解决:跳转 TabBar 页面时,URL 必须完全匹配 pages.json 中的配置路径,不能携带任何 query 参数。需要传参请使用 Pinia / Storage / 事件总线。
坑点二:缓存导致"看起来没刷新"
- 现象:调用 reLaunch 跳转到当前页面,但页面数据没有更新。
- 原因:路由复用机制可能导致页面实例被缓存。
- 解决 :在 URL 后拼接时间戳参数(如
?_t=Date.now()),强制触发页面重建。
坑点三:在下拉刷新回调中使用导致动画卡死
- 现象:在 onPullDownRefresh 中调用 reLaunch,下拉刷新动画一直转圈不消失。
- 解决 :不要在 onPullDownRefresh 中混用
uni.reLaunch。如果确实需要重载,应先调用uni.stopPullDownRefresh()停止动画,或使用数据重拉方案替代。
坑点四:重复点击导致 locked 错误
- 现象 :快速连续点击按钮,控制台报错
reLaunch:fail pages/index/index locked。 - 原因:第一次 reLaunch 正在执行时,再次调用会被锁定。
- 解决:添加防重复点击机制(导航锁),确保跳转操作不会连续触发。
坑点五:生命周期触发异常
- 现象:跳转到 TabBar 页面后,onShow / onLoad 没有触发,导致定时器或数据请求未执行。
- 原因:TabBar 页面在应用启动时已创建,reLaunch 可能只触发 onShow 而不触发 onLoad,具体表现因平台而异。
- 解决:将数据初始化逻辑放在 onShow 中,或改用 switchTab + 事件通知的方式。
坑点六:H5 端浏览器历史记录无法清空
- 现象:H5 端调用 reLaunch 后,点击浏览器返回按钮仍能回到之前的页面。
- 原因:reLaunch 只清空了 uni-app 内部的页面栈,无法清除浏览器自身的历史记录。
- 解决 :H5 端如需完全控制浏览器历史,需配合
history.replaceState或location.replace处理。
坑点七:部分安卓低端机白屏/闪退
- 现象:调用 reLaunch 后页面白屏或应用闪退,无报错信息。
- 原因:页面栈被瞬间全部销毁重建,低端机性能不足或存在 onUnload 中的异步操作冲突。
- 解决:确保所有页面的 onUnload 中不要执行耗时的异步操作(如在 onUnload 中调用 navigateBack);条件允许时优先使用"数据重拉 + 手动 reset"方案替代 reLaunch。
坑点八:不支持过渡动画配置
- 现象:设置了 animationType 参数但跳转无动画效果。
- 解决 :reLaunch 是原子操作,不支持 animationType 等过渡配置,跳转过程无动画。如需动画效果,请改用
uni.navigateTo或uni.redirectTo。
五、switchTab
1. 作用
跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。它专门用于底部导航栏(TabBar)的切换。
2. 用法
基础跳转:
javascript
uni.switchTab({
url: '/pages/index/index'
});
目标页面接收数据(Vue3 setup):
由于 switchTab 不支持 URL 传参,通常使用全局状态管理(如 Pinia)或本地缓存(Storage)来传递数据:
javascript
// 跳转前存储数据
uni.setStorageSync('tabData', { keyword: 'test' });
uni.switchTab({ url: '/pages/index/index' });
vue
// 目标页面获取数据
<script setup>
import { onShow } from '@dcloudio/uni-app';
onShow(() => {
const data = uni.getStorageSync('tabData');
console.log(data); // { keyword: 'test' }
});
</script>
3. 避坑指南
坑点一:不支持 URL 传参
- 现象 :URL 后面拼接了
?id=123,但目标页面的 onLoad 中拿不到参数。 - 原因:TabBar 页面首次加载后会被缓存,后续切换只触发 onShow 而不触发 onLoad,因此无法接收 URL 参数。
- 解决 :必须使用 Pinia、Vuex、
uni.setStorageSync或全局变量进行数据传递。
坑点二:路径必须完全匹配
- 现象:跳转静默失败,控制台报 warning。
- 原因 :url 必须是 pages.json 中
tabBar.list里配置的真实路径,不能携带任何 query 参数,也不能加.vue后缀。 - 解决 :检查
url是否与pages.json中tabBar.list配置的页面路径完全一致,不要添加额外参数或文件后缀。
坑点三:App 端偶发闪白/闪退
- 现象:从深层页面调用 switchTab 跳回首页时,页面快速闪动一下白色,或先退回手机桌面再显示首页。
- 原因:这是 uni-app 在部分 App 端的已知渲染 Bug,通常与同时销毁大量非 Tab 页面有关。
- 解决 :可尝试使用
uni.reLaunch替代,或延迟跳转(如setTimeout100ms);确保 HBuilderX 升级到较新的正式版本。
坑点四:H5 端路由初始化问题
- 现象 :在应用启动初期(如 onLaunch 中)立即调用 switchTab,H5 端可能报错
Cannot read properties of undefined (reading 'replace')。 - 原因:应用启动初期 uni-app 的路由对象尚未完成初始化,此时调用 switchTab 会访问到尚未就绪的路由实例。
- 解决:确保在 onReady 生命周期之后再调用 switchTab,或使用 setTimeout 延迟执行。
六、navigateBack
1. 作用
关闭当前页面,返回上一页面或多级页面。它是 uni.navigateTo 等 API 的逆操作。
2. 用法
返回上一页:
javascript
uni.navigateBack();
返回指定层级:
javascript
// 返回上上个页面
uni.navigateBack({
delta: 2
});
3. 避坑指南
坑点一:H5 端刷新后失效(静默失败)
- 现象:在 H5 端刷新页面后,点击返回按钮毫无反应。
- 原因 :H5 刷新会清空 uni-app 运行时维护的虚拟页面栈,导致
getCurrentPages()仅剩当前页,navigateBack 找不到上一页。 - 解决 :封装安全返回方法,当页面栈长度
<= 1时,降级使用浏览器原生能力history.back()或history.go(-delta)。
坑点二:在 onBackPress 中死循环
- 现象 :在 onBackPress 生命周期中调用
uni.navigateBack(),导致页面卡死或无限触发返回。 - 原因 :
uni.navigateBack()本身也会触发 onBackPress。 - 解决 :在 onBackPress 中判断来源
options.from,当来源为'navigateBack'时直接return false放行,避免死循环。
坑点三:拦截异步操作导致提前返回
- 现象:在 onBackPress 中弹出确认框(showModal),但用户还没点击确定,页面就已经退回去了。
- 原因:showModal 是异步的,而 onBackPress 是同步执行的,函数执行完就放行了。
- 解决 :在 onBackPress 中先
return true阻止默认返回,然后在弹窗的回调中再手动调用uni.navigateBack()。
坑点四:Web-view 冲突
- 现象:在 App 中使用 web-view 加载 H5,点击返回时只退回了 H5 的上一页,没有退出 Web-view 组件。
- 原因:App 端的返回键默认优先触发 Web-view 内部 H5 的路由返回。
- 解决 :在 Web-view 所在页面的 onBackPress 中,通过 plus API 获取 Web-view 对象,判断 H5 是否还有历史记录,若无则手动关闭 Web-view 并调用
uni.navigateBack()。
坑点五:delta 超出页面栈深度
- 现象:传入的 delta 值大于当前页面栈层数,返回行为不符合预期。
- 原因 :
navigateBack的 delta 参数表示要回退的层数,超出可回退范围时,不同平台会采用兜底策略(如直接回到首页),与预期可能不一致。 - 解决 :跳转前使用
getCurrentPages()获取当前页面栈长度,动态计算安全的 delta 值;如果 delta 大于现有页面数,系统会自动返回到首页。