uni-app 路由详解:从入门到精通
本文基于 uni-app 页面路由文档 整理,详细介绍了 uni-app 中的路由 API 使用方法和最佳实践。
目录
- 概述
- [路由 API 详解](#路由 API 详解 "#%E8%B7%AF%E7%94%B1-api-%E8%AF%A6%E8%A7%A3")
- [uni.navigateTo - 保留当前页面跳转](#uni.navigateTo - 保留当前页面跳转 "#uninavigateto---%E4%BF%9D%E7%95%99%E5%BD%93%E5%89%8D%E9%A1%B5%E9%9D%A2%E8%B7%B3%E8%BD%AC")
- [uni.redirectTo - 关闭当前页面跳转](#uni.redirectTo - 关闭当前页面跳转 "#uniredirectto---%E5%85%B3%E9%97%AD%E5%BD%93%E5%89%8D%E9%A1%B5%E9%9D%A2%E8%B7%B3%E8%BD%AC")
- [uni.reLaunch - 关闭所有页面跳转](#uni.reLaunch - 关闭所有页面跳转 "#unirelaunch---%E5%85%B3%E9%97%AD%E6%89%80%E6%9C%89%E9%A1%B5%E9%9D%A2%E8%B7%B3%E8%BD%AC")
- [uni.switchTab - 跳转到 tabBar 页面](#uni.switchTab - 跳转到 tabBar 页面 "#uniswitchtab---%E8%B7%B3%E8%BD%AC%E5%88%B0-tabbar-%E9%A1%B5%E9%9D%A2")
- [uni.navigateBack - 返回上一页](#uni.navigateBack - 返回上一页 "#uninavigateback---%E8%BF%94%E5%9B%9E%E4%B8%8A%E4%B8%80%E9%A1%B5")
- [页面间通信 - EventChannel](#页面间通信 - EventChannel "#%E9%A1%B5%E9%9D%A2%E9%97%B4%E9%80%9A%E4%BF%A1---eventchannel")
- 窗口动画配置
- 注意事项和最佳实践
- 总结
概述
uni-app 提供了丰富的路由 API,用于实现页面之间的跳转和导航。根据不同的使用场景,可以选择不同的路由方法。理解这些 API 的区别和使用场景,对于开发高质量的 uni-app 应用至关重要。
路由 API 详解
uni.navigateTo - 保留当前页面跳转
功能说明 :保留当前页面,跳转到应用内的某个页面。使用 uni.navigateBack 可以返回到原页面。
适用场景:
- 需要返回的页面跳转
- 详情页、表单页等需要保留历史记录的页面
参数说明:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| url | String | 是 | 需要跳转的应用内非 tabBar 的页面的路径,路径后可以带参数 |
| animationType | String | 否 | 窗口显示的动画效果(仅 App 支持) |
| animationDuration | Number | 否 | 窗口动画持续时间,单位为 ms(仅 App 支持) |
| events | Object | 否 | 页面间通信接口,用于监听被打开页面发送到当前页面的数据(2.8.9+) |
| success | Function | 否 | 接口调用成功的回调函数 |
| fail | Function | 否 | 接口调用失败的回调函数 |
| complete | Function | 否 | 接口调用结束的回调函数 |
代码示例:
javascript
// 在起始页面跳转到 test.vue 页面并传递参数
uni.navigateTo({
url: 'test?id=1&name=uniapp',
success: (res) => {
console.log('跳转成功', res)
},
fail: (err) => {
console.log('跳转失败', err)
}
})
// 在 test.vue 页面接收参数
export default {
onLoad: function (option) {
console.log(option.id) // 输出: 1
console.log(option.name) // 输出: uniapp
}
}
传递复杂参数:
javascript
// 传递对象参数(需要序列化)
const data = {
id: 1,
name: 'uniapp',
list: [1, 2, 3]
}
uni.navigateTo({
url: `test?data=${encodeURIComponent(JSON.stringify(data))}`
})
// 接收参数
onLoad((options) => {
const data = JSON.parse(decodeURIComponent(options.data))
console.log(data)
})
uni.redirectTo - 关闭当前页面跳转
功能说明:关闭当前页面,跳转到应用内的某个页面。
适用场景:
- 登录成功后跳转到首页
- 不需要返回的页面跳转
- 替换当前页面
参数说明 :与 uni.navigateTo 相同(除了不支持 events 参数)
代码示例:
javascript
// 登录成功后跳转到首页
uni.redirectTo({
url: '/pages/index/index'
})
与 navigateTo 的区别:
javascript
// A 页面
uni.navigateTo({
url: 'B?id=1'
})
// B 页面
uni.navigateTo({
url: 'C?id=1'
})
// 在 C 页面内 navigateBack,将返回 B 页面
// 但如果 B 页面使用的是 redirectTo,则返回 A 页面
uni.reLaunch - 关闭所有页面跳转
功能说明:关闭所有页面,打开到应用内的某个页面。
适用场景:
- 退出登录后跳转到登录页
- 需要清空页面栈的场景
- 重新初始化应用状态
代码示例:
javascript
// 退出登录
const logout = () => {
// 清除用户信息
uni.removeStorageSync('token')
// 关闭所有页面,跳转到登录页
uni.reLaunch({
url: '/pages/login/login'
})
}
uni.switchTab - 跳转到 tabBar 页面
功能说明:跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
适用场景:
- 切换到底部导航栏页面
- 从非 tabBar 页面返回到 tabBar 页面
重要提示:
- 只能跳转到
pages.json中配置的tabBar页面 - 跳转的 url 必须是在
tabBar中定义的路径
代码示例:
javascript
// 跳转到首页(tabBar 页面)
uni.switchTab({
url: '/pages/index/index'
})
pages.json 配置示例:
json
{
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/user/user",
"text": "我的"
}
]
}
}
uni.navigateBack - 返回上一页
功能说明:关闭当前页面,返回上一页面或多级页面。
参数说明:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| delta | Number | 否 | 返回的页面数,如果 delta 大于现有页面数,则返回到首页。默认值为 1 |
| animationType | String | 否 | 窗口关闭的动画效果(仅 App 支持) |
| animationDuration | Number | 否 | 窗口关闭动画的持续时间,单位为 ms(仅 App 支持) |
代码示例:
javascript
// 返回上一页
uni.navigateBack()
// 返回上两页
uni.navigateBack({
delta: 2
})
// 带动画效果返回(仅 App)
uni.navigateBack({
delta: 1,
animationType: 'pop-out',
animationDuration: 300
})
实际应用场景:
javascript
// A 页面 -> B 页面 -> C 页面
// 在 C 页面内 navigateBack,将返回 B 页面
uni.navigateBack({
delta: 1
})
// 如果想直接返回 A 页面
uni.navigateBack({
delta: 2
})
页面间通信 - EventChannel
2.8.9+ 支持,HarmonyOS Next 不支持
EventChannel 提供了页面间事件通信的能力,可以在页面跳转时建立通信通道。
EventChannel 方法
emit - 触发事件
javascript
// 在目标页面触发事件
eventChannel.emit('eventName', { data: 'value' })
on - 持续监听事件
javascript
// 在源页面监听事件
eventChannel.on('eventName', (data) => {
console.log('接收到数据:', data)
})
once - 监听事件一次
javascript
// 只监听一次,触发后失效
eventChannel.once('eventName', (data) => {
console.log('接收到数据:', data)
})
off - 取消监听
javascript
// 取消所有监听
eventChannel.off('eventName')
// 取消指定的监听函数
eventChannel.off('eventName', fn)
完整示例
javascript
// 源页面 - 发送数据
uni.navigateTo({
url: '/pages/detail/detail',
events: {
// 监听目标页面发送的事件
acceptDataFromDetail: (data) => {
console.log('从详情页接收到的数据:', data)
}
},
success: (res) => {
// 通过 eventChannel 向目标页面发送数据
res.eventChannel.emit('acceptDataFromOpenerPage', {
data: '来自源页面的数据'
})
}
})
// 目标页面 - 接收和发送数据
export default {
onLoad(options, context) {
// 接收源页面发送的数据
context.eventChannel.on('acceptDataFromOpenerPage', (data) => {
console.log('接收到源页面的数据:', data)
})
// 向源页面发送数据
context.eventChannel.emit('acceptDataFromDetail', {
data: '来自详情页的数据'
})
}
}
窗口动画配置
本功能仅 App 支持。小程序自身不支持自定义动画。
uni-app 支持在 API、组件、pages.json 中配置窗口动画,优先级为:API > 组件 > pages.json。
API 配置
javascript
// 跳转时配置动画
uni.navigateTo({
url: '../test/test',
animationType: 'pop-in',
animationDuration: 200
})
// 返回时配置动画
uni.navigateBack({
delta: 1,
animationType: 'pop-out',
animationDuration: 200
})
组件配置
html
<navigator
animation-type="pop-in"
animation-duration="300"
url="../test/test">
跳转
</navigator>
<navigator
animation-type="pop-out"
animation-duration="300"
open-type="navigateBack">
返回
</navigator>
pages.json 配置
json
{
"style": {
"app-plus": {
"animationType": "fade-in",
"animationDuration": 300
}
}
}
支持的动画类型
| 显示动画 | 关闭动画 | 说明 |
|---|---|---|
| slide-in-right | slide-out-right | 新窗体从右侧进入 |
| slide-in-left | slide-out-left | 新窗体从左侧进入 |
| slide-in-top | slide-out-top | 新窗体从顶部进入 |
| slide-in-bottom | slide-out-bottom | 新窗体从底部进入 |
| pop-in | pop-out | 新窗体从左侧进入,且老窗体被挤压而出 |
| fade-in | fade-out | 新窗体从透明到不透明逐渐显示 |
| zoom-out | zoom-in | 新窗体从小到大缩放显示 |
| zoom-fade-out | zoom-fade-in | 新窗体从小到大逐渐放大并且从透明到不透明逐渐显示 |
| none | none | 无动画 |
注意事项和最佳实践
1. 路由限制
navigateTo、redirectTo只能打开非 tabBar 页面switchTab只能打开 tabBar 页面reLaunch可以打开任意页面
2. 页面栈管理
javascript
// 注意页面栈的层级
// A 页面
uni.navigateTo({
url: 'B?id=1'
})
// B 页面
uni.navigateTo({
url: 'C?id=1'
})
// 在 C 页面内 navigateBack,将返回 B 页面
// 如果 B 页面使用的是 redirectTo,则返回 A 页面
3. H5 端特殊处理
H5 端页面刷新之后页面栈会消失,此时 navigateBack 不能返回。如果需要返回,可以使用 history.back() 导航到浏览器的其他历史记录。
javascript
// #ifdef H5
if (getCurrentPages().length === 1) {
history.back()
} else {
uni.navigateBack()
}
// #endif
4. 不能在首页 onReady 之前进行页面跳转
javascript
export default {
onReady() {
// 正确的做法:在 onReady 之后跳转
uni.navigateTo({
url: '/pages/detail/detail'
})
}
}
5. 参数传递最佳实践
javascript
// ✅ 推荐:简单参数使用 URL 参数
uni.navigateTo({
url: `/pages/detail/detail?id=${id}&name=${name}`
})
// ✅ 推荐:复杂对象使用 JSON 序列化
const complexData = {
user: { id: 1, name: 'test' },
list: [1, 2, 3]
}
uni.navigateTo({
url: `/pages/detail/detail?data=${encodeURIComponent(JSON.stringify(complexData))}`
})
// ✅ 推荐:使用 EventChannel 进行页面间通信
uni.navigateTo({
url: '/pages/detail/detail',
events: {
updateData: (data) => {
// 处理数据更新
}
}
})
6. 避免过度使用 navigateTo 导致页面栈问题
常见问题场景:
我遇到的问题:在开发中习惯性地使用 uni.navigateTo 进行所有页面跳转,这会导致页面栈管理出现问题。
问题示例:
javascript
// ❌ 错误示例:表单页 -> 列表页 -> 详情页
// 表单页填写完成
const submitForm = () => {
uni.navigateTo({
url: '/pages/list/list' // 问题:应该使用 redirectTo
})
}
// 列表页点击 item
const goToDetail = (id) => {
uni.navigateTo({
url: `/pages/detail/detail?id=${id}` // 问题:页面栈过深
})
}
问题分析:
- 表单页提交后,通常不需要再返回表单页,应该使用
redirectTo替换当前页面 - 页面栈过深会导致返回逻辑混乱,用户体验不佳
- 可能导致内存占用过高(页面栈中保留过多页面)
正确的解决方案:
javascript
// ✅ 正确示例 1:表单页提交后替换为列表页
const submitForm = () => {
uni.redirectTo({
url: '/pages/list/list' // 关闭表单页,打开列表页
})
}
// ✅ 正确示例 2:如果列表页是 tabBar 页面
const submitForm = () => {
uni.switchTab({
url: '/pages/list/list' // 切换到 tabBar 页面
})
}
// ✅ 正确示例 3:详情页需要返回列表页(使用 navigateTo)
const goToDetail = (id) => {
uni.navigateTo({
url: `/pages/detail/detail?id=${id}` // 可以返回列表页
})
}
// ✅ 正确示例 4:详情页需要直接返回表单页
const goToDetail = (id) => {
uni.navigateTo({
url: `/pages/detail/detail?id=${id}`
})
}
// 在详情页返回时,如果需要跳过列表页
const goBack = () => {
uni.navigateBack({
delta: 2 // 返回上两页(跳过列表页)
})
}
最佳实践建议:
- 表单提交后 → 使用
redirectTo或switchTab(如果是 tabBar 页面) - 需要返回的页面 → 使用
navigateTo(如详情页、编辑页) - 不需要返回的页面 → 使用
redirectTo(如登录后跳转首页) - 清空页面栈 → 使用
reLaunch(如退出登录) - 控制页面栈深度 → 避免超过 10 层页面栈,及时使用
redirectTo替换不需要返回的页面
页面栈深度检查:
javascript
// 检查当前页面栈深度
const pages = getCurrentPages()
console.log('当前页面栈深度:', pages.length)
// 如果页面栈过深,考虑使用 redirectTo
if (pages.length >= 10) {
uni.redirectTo({
url: '/pages/target/target'
})
} else {
uni.navigateTo({
url: '/pages/target/target'
})
}
总结
uni-app 的路由系统提供了灵活且强大的页面导航能力。正确理解和使用这些 API,可以帮助我们:
- 优化用户体验:选择合适的跳转方式和动画效果
- 管理页面栈:合理控制页面层级,避免内存问题
- 实现页面通信:通过 EventChannel 实现页面间的数据传递
- 提升开发效率:使用合适的路由方法简化代码逻辑
在实际开发中,建议根据具体场景选择合适的路由方法:
- 需要返回 → 使用
navigateTo - 不需要返回 → 使用
redirectTo - 清空所有页面 → 使用
reLaunch - 跳转 tabBar → 使用
switchTab - 返回上一页 → 使用
navigateBack
希望本文能帮助你更好地理解和使用 uni-app 的路由系统!
参考文档: