1 uni-app路由基础概念
uni-app的路由系统与一般Web应用有所不同,它基于小程序架构 进行设计,这意味着开发者无需像传统Vue项目那样手动配置路由映射。在uni-app中,路由管理变得十分简单直观,开发者只需在pages.json文件中配置页面路径,框架便会自动处理页面之间的导航关系。
1.1 路由机制简介
uni-app的路由机制建立在页面栈 概念之上。每当跳转到新页面时,该页面会被压入栈顶;返回时,则从栈顶移除页面。这种管理方式与原生小程序体验一致,保证了多端兼容性。需要注意的是,uni-app的路由配置与Vue Router不同,页面路径必须在pages.json中注册才能进行有效跳转。
1.2 路由配置方法
在uni-app项目中,所有页面路由均在pages.json中进行配置。下面是一个典型的路由配置示例:
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页",
"navigationBarBackgroundColor": "#FFFFFF"
}
},
{
"path": "pages/detail/detail",
"style": {
"navigationBarTitleText": "详情页",
"enablePullDownRefresh": true
}
}
],
"tabBar": {
"list": [
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/profile/profile",
"text": "我的"
}
]
}
}
在以上配置中,pages数组中的第一项表示应用启动页,即用户打开应用时首先显示的页面。每个页面可以配置自己的样式属性,如导航栏标题、背景色等。
2 页面跳转API详解
uni-app提供了多种页面跳转API,每种方法都有其特定的使用场景和页面栈行为。理解这些差异对于构建流畅的用户体验至关重要。下面通过表格形式对比各种跳转方法的特点:
| 方法 | 页面栈表现 | 适用场景 | 参数传递限制 |
|---|---|---|---|
uni.navigateTo |
保留当前页面,新页面入栈 | 普通页面跳转,需要返回 | 支持URL参数 |
uni.redirectTo |
当前页面出栈,新页面入栈 | 登录后跳转,无需返回 | 支持URL参数 |
uni.reLaunch |
关闭所有页面,打开新页面 | 应用重启或重要页面跳转 | tabBar页面不可带参 |
uni.switchTab |
关闭所有非tabBar页面 | 切换底部导航页面 | 不可传递URL参数 |
uni.navigateBack |
页面出栈,回到上级页面 | 返回上一页或多级页面 | 需通过其他方式传参 |
2.1 uni.navigateTo:保留当前页面的跳转
uni.navigateTo是最常用的跳转方法,它会保留当前页面(即当前页面仅被隐藏而非销毁),并将目标页面压入页面栈顶。这意味着用户可以通过返回按钮或navigateBack方法轻松回到来源页面。
// 简单页面跳转
uni.navigateTo({
url: '/pages/detail/detail'
});
// 带参数跳转
uni.navigateTo({
url: '/pages/detail/detail?id=123&title=示例标题'
});
// 传递对象等复杂参数(需要编码)
const productInfo = {
id: 123,
name: '商品名称',
price: 99.9
};
uni.navigateTo({
url: '/pages/detail/detail?data=' + encodeURIComponent(JSON.stringify(productInfo))
});
注意事项:
- 跳转路径必须是
pages.json中注册的非tabBar页面 - URL参数有长度限制,建议不要传递大量数据
- 页面跳转有层级限制,一般最多不超过10级
2.2 uni.redirectTo:重定向跳转
与navigateTo不同,redirectTo会关闭当前页面(即从页面栈中移除),然后跳转到新页面。这种方法适用于那些不需要返回的场景,如用户登录后跳转到首页。
// 登录成功后跳转首页
uni.redirectTo({
url: '/pages/home/home'
});
// 表单提交后跳转到结果页
uni.redirectTo({
url: '/pages/result/result'
});
2.3 uni.switchTab:切换Tab页面
当需要跳转到底部TabBar页面时,必须使用switchTab方法。调用该方法后,所有非tabBar页面将被关闭,只留下目标tabBar页面。
// 跳转到TabBar页面
uni.switchTab({
url: '/pages/home/home'
});
重要限制:
- 只能跳转已在
pages.json的tabBar配置中注册的页面 - url参数无法传递,因为跳转的是tabBar页面
- 动画效果与普通页面跳转不同,遵循tab切换动画
2.4 uni.reLaunch:重新启动应用
reLaunch方法会关闭所有已打开的页面,然后打开指定页面。这相当于应用的一次"重启",常用于重要切换如用户登出后返回登录页。
// 退出登录后跳转到登录页
uni.reLaunch({
url: '/pages/login/login'
});
// 跳转到首页并重置应用状态
uni.reLaunch({
url: '/pages/index/index'
});
2.5 uni.navigateBack:返回上一页
navigateBack用于返回上一级或多级页面,通过delta参数指定返回的层数。
// 返回上一页
uni.navigateBack();
// 返回前两页(delta为2)
uni.navigateBack({
delta: 2
});
// 带动画效果的返回
uni.navigateBack({
delta: 1,
animationType: 'pop-out',
animationDuration: 300
});
在实际开发中,可以通过getCurrentPages()方法获取当前页面栈信息,动态确定需要返回的层数:
const pages = getCurrentPages();
// 根据业务逻辑计算需要返回的层数
if (pages.length > 1) {
uni.navigateBack({
delta: 1
});
} else {
uni.switchTab({
url: '/pages/home/home'
});
}
3 参数传递与接收方式
页面跳转过程中的参数传递是开发中的常见需求。uni-app提供了多种方式来实现数据在页面间的传递,每种方式各有适用场景。
3.1 URL参数传递与接收
URL传参是最简单直接的参数传递方式,适用于传递基本数据类型和简单的数据结构。
传递参数
// 传递基本参数
uni.navigateTo({
url: '/pages/detail/detail?id=123&title=商品标题'
});
// 传递对象等复杂数据(需要序列化和编码)
const product = {
id: 456,
name: '商品名称',
specs: {
color: '红色',
size: 'XL'
}
};
uni.navigateTo({
url: '/pages/detail/detail?product=' + encodeURIComponent(JSON.stringify(product))
});
接收参数
在目标页面的onLoad生命周期函数中,可以获取到传递的参数:
// pages/detail/detail.vue
export default {
data() {
return {
productId: '',
productTitle: '',
productInfo: null
};
},
onLoad(options) {
// 接收基本参数
this.productId = options.id;
this.productTitle = options.title;
// 接收复杂对象参数
if (options.product) {
this.productInfo = JSON.parse(decodeURIComponent(options.product));
}
console.log('接收到的参数:', options);
}
};
注意事项:
- URL参数有长度限制,不适合传递大量数据
- 敏感数据不应通过URL传递,可能被泄露
- 对象数组等复杂数据需要序列化和编码处理
3.2 事件通道(Event Channel)传参
事件通道提供了页面间双向通信的能力,允许页面在跳转过程中建立一条通信渠道,不仅可以传递初始数据,还可以实现后续的事件通信。
创建事件通道
// 在起始页面
uni.navigateTo({
url: '/pages/detail/detail?id=123',
events: {
// 定义可以从目标页面接收的事件
acceptDataFromOpenedPage: (data) => {
console.log('从目标页面接收的数据:', data);
},
someEvent: (data) => {
console.log('某些事件数据:', data);
}
},
success: (res) => {
// 通过事件通道向目标页面发送数据
res.eventChannel.emit('acceptDataFromOpenerPage', {
data: '来自起始页面的数据'
});
}
});
在目标页面使用事件通道
// 在目标页面中
export default {
onLoad(options) {
// 获取事件通道
const eventChannel = this.getOpenerEventChannel();
// 监听起始页面发送的事件
eventChannel.on('acceptDataFromOpenerPage', (data) => {
console.log('接收到起始页面的数据:', data);
});
// 向起始页面发送数据
eventChannel.emit('acceptDataFromOpenedPage', {
data: '来自目标页面的数据'
});
}
};
事件通道特别适合需要持续通信的页面关系,如主页面与详情页、表单页与选择页等场景。
3.3 全局状态管理与缓存传参
对于复杂应用或在多个页面间需要共享的数据,可以使用全局状态管理或本地缓存方式传参。
使用Vuex进行状态管理
// store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
userInfo: null,
currentProduct: null
},
mutations: {
setUserInfo(state, userInfo) {
state.userInfo = userInfo;
},
setCurrentProduct(state, product) {
state.currentProduct = product;
}
},
actions: {
updateProduct({ commit }, product) {
commit('setCurrentProduct', product);
// 跳转到详情页
uni.navigateTo({
url: '/pages/detail/detail'
});
}
}
});
在页面中使用Vuex状态:
// 页面A:设置数据并跳转
this.$store.dispatch('updateProduct', product);
// 页面B:获取数据
import { mapState } from 'vuex';
export default {
computed: {
...mapState(['currentProduct'])
},
onLoad() {
console.log('当前产品信息:', this.currentProduct);
}
};
使用本地缓存传参
// 页面A:存储数据并跳转
const product = {
id: 123,
name: '商品名称',
price: 99.9
};
// 同步方式
uni.setStorageSync('currentProduct', product);
// 异步方式
uni.setStorage({
key: 'currentProduct',
data: product,
success: () => {
uni.navigateTo({
url: '/pages/detail/detail'
});
}
});
// 页面B:读取数据
export default {
onLoad() {
// 同步方式读取
const product = uni.getStorageSync('currentProduct');
// 异步方式读取
uni.getStorage({
key: 'currentProduct',
success: (res) => {
this.productInfo = res.data;
}
});
}
};
4 高级应用与最佳实践
掌握了uni-app路由的基础用法后,了解一些高级技巧和最佳实践能够帮助您构建更加稳定高效的应用。
4.1 分包加载与预下载
随着应用功能增加,代码包体积会不断增大。uni-app支持分包加载机制,将应用分成多个子包,按需加载,提升应用启动速度。
分包配置
{
"pages": [
{
"path": "pages/index/index",
"style": {}
}
],
"subPackages": [
{
"root": "pagesA",
"pages": [
{
"path": "list/list",
"style": {}
},
{
"path": "detail/detail",
"style": {}
}
]
},
{
"root": "pagesB",
"pages": [
{
"path": "user/user",
"style": {}
}
]
}
],
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["pagesA"]
}
}
}
分包预下载
通过预下载规则,可以在进入某个页面时自动预下载可能需要的分包:
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["pagesA"]
}
}
4.2 路由拦截与权限控制
对于需要登录验证的页面,可以通过路由拦截实现权限控制。
实现路由拦截器
// 路由拦截器
const routeInterceptor = {
// 前置拦截
beforeEach(to, from, next) {
// 获取token
const token = uni.getStorageSync('token');
// 检查目标页面是否需要认证
if (to.meta && to.meta.requiresAuth && !token) {
// 跳转到登录页
uni.redirectTo({
url: '/pages/login/login?redirect=' + encodeURIComponent(to.path)
});
} else {
next();
}
}
};
// 封装导航方法,加入拦截逻辑
const myNavigateTo = (url, requiresAuth = false) => {
if (requiresAuth) {
const token = uni.getStorageSync('token');
if (!token) {
uni.redirectTo({
url: '/pages/login/login?redirect=' + encodeURIComponent(url)
});
return;
}
}
uni.navigateTo({ url });
};
// 使用自定义导航方法
myNavigateTo('/pages/profile/profile', true);
页面元信息配置
在页面路由中配置元信息,声明页面的权限要求:
// 在页面组件中
export default {
meta: {
requiresAuth: true // 需要登录才能访问
},
// ...其他配置
}
4.3 性能优化与注意事项
-
控制页面层级:uni-app有页面层级限制(通常10层),避免过深嵌套跳转
-
合理使用跳转方式:
- 普通跳转使用
navigateTo - 不需要返回的场景使用
redirectTo - TabBar页面跳转使用
switchTab
- 普通跳转使用
-
参数传递优化:
- 避免通过URL传递大量数据
- 复杂数据使用全局状态或缓存传递
- 及时清理不再需要的缓存数据
-
错误处理:
uni.navigateTo({
url: '/pages/detail/detail',
fail: (error) => {
console.error('页面跳转失败:', error);
uni.showToast({
title: '页面跳转失败',
icon: 'none'
});
}
});
5 总结
uni-app的路由系统设计既考虑了小程序的特性,又兼顾了Vue开发者的习惯。通过本文的详细介绍,相信您已经掌握了:
- 五种核心跳转方法的特点和适用场景
- 多种参数传递方式及其应用场景
- 高级特性如分包加载和路由拦截
- 性能优化和错误处理的最佳实践
在实际项目中,建议根据具体需求选择合适的跳转方式和参数传递方法。对于简单数据传递,URL参数是最便捷的选择;对于复杂数据或需要双向通信的场景,事件通道更为合适;而对于全局共享数据,Vuex或本地缓存是更好的选择。
uni-app路由系统的灵活性和强大功能,能够满足各种复杂应用的导航需求,正确使用这些功能将大大提升应用的用户体验和开发效率。