uni-app路由与页面跳转:最佳实践与踩坑指南 0 次阅读

路由与页面跳转是uni-app应用的核心功能之一,本文将详细介绍各种跳转方式及其最佳实践,帮助你构建流畅的页面导航体验。

1. 基础路由方法

1.1 页面跳转方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 保留当前页面,跳转到应用内的某个页面
uni.navigateTo({
url: '/pages/detail/detail?id=1',
success: function(res) {
console.log('跳转成功')
},
fail: function(err) {
console.error('跳转失败:', err)
}
})

// 关闭当前页面,跳转到应用内的某个页面
uni.redirectTo({
url: '/pages/index/index'
})

// 关闭所有页面,打开到应用内的某个页面
uni.reLaunch({
url: '/pages/home/home'
})

// 关闭当前页面,返回上一页面或多级页面
uni.navigateBack({
delta: 1
})

// 跳转到 tabBar 页面
uni.switchTab({
url: '/pages/user/user'
})

1.2 参数传递

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 页面A:传递参数
uni.navigateTo({
url: '/pages/detail/detail?id=1&type=product&data=' + encodeURIComponent(JSON.stringify(data))
})

// 页面B:接收参数
export default {
onLoad(options) {
const id = options.id
const type = options.type
const data = JSON.parse(decodeURIComponent(options.data))
console.log('接收到的参数:', id, type, data)
}
}

2. 路由拦截与权限控制

2.1 全局路由拦截

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// main.js
import Vue from 'vue'
import store from './store'

// 注册全局路由拦截器
const whiteList = ['/pages/login/login', '/pages/register/register']

Vue.prototype.$beforeRouter = function(to) {
return new Promise((resolve, reject) => {
// 检查是否需要登录
if (whiteList.includes(to)) {
resolve()
return
}

// 检查登录状态
const token = uni.getStorageSync('token')
if (!token) {
uni.showToast({
title: '请先登录',
icon: 'none'
})
uni.navigateTo({
url: '/pages/login/login'
})
reject(new Error('未登录'))
return
}

// 检查权限
const userInfo = store.state.user.userInfo
if (to.requiresAuth && !userInfo.permissions.includes(to.permission)) {
uni.showToast({
title: '暂无权限访问',
icon: 'none'
})
reject(new Error('无权限'))
return
}

resolve()
})
}

// 页面中使用
export default {
async onLoad() {
try {
await this.$beforeRouter('/pages/user/user')
// 继续执行页面逻辑
} catch (err) {
console.error('路由拦截:', err)
}
}
}

2.2 页面级权限控制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// mixins/auth.js
export default {
data() {
return {
hasPermission: false
}
},
onLoad() {
this.checkPermission()
},
methods: {
checkPermission() {
const userPermissions = this.$store.state.user.permissions
const pagePermission = this.$options.permission

if (!pagePermission) {
this.hasPermission = true
return
}

this.hasPermission = userPermissions.includes(pagePermission)

if (!this.hasPermission) {
uni.showModal({
title: '提示',
content: '暂无访问权限',
showCancel: false,
success: () => {
uni.navigateBack()
}
})
}
}
}
}

// 页面中使用
import authMixin from '@/mixins/auth'

export default {
mixins: [authMixin],
permission: 'user:edit'
}

3. 页面通信方案

3.1 页面间事件通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 页面A:发送事件
onLoad() {
// 注册事件监听
uni.$on('updateList', this.handleUpdateList)
},
onUnload() {
// 注销事件监听
uni.$off('updateList', this.handleUpdateList)
},
methods: {
handleUpdateList(data) {
console.log('收到更新数据:', data)
this.refreshList()
}
}

// 页面B:触发事件
methods: {
submitSuccess() {
uni.$emit('updateList', { type: 'add', data: this.formData })
uni.navigateBack()
}
}

3.2 页面栈管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// utils/page.js
class PageManager {
// 获取当前页面栈
static getCurrentPages() {
const pages = getCurrentPages()
return pages
}

// 获取上一个页面实例
static getPrevPage(delta = 1) {
const pages = this.getCurrentPages()
const prevPage = pages[pages.length - 1 - delta]
return prevPage
}

// 调用上一个页面的方法
static callPrevPageMethod(methodName, args, delta = 1) {
const prevPage = this.getPrevPage(delta)
if (prevPage && typeof prevPage[methodName] === 'function') {
return prevPage[methodName](args)
}
return null
}

// 检查是否可以返回
static canBack() {
const pages = this.getCurrentPages()
return pages.length > 1
}
}

export default PageManager

// 使用示例
import PageManager from '@/utils/page'

// 调用上一页面方法
PageManager.callPrevPageMethod('refreshData', { type: 'update' })

// 检查是否可以返回
if (PageManager.canBack()) {
uni.navigateBack()
} else {
uni.reLaunch({ url: '/pages/index/index' })
}

4. 路由动画与转场效果

4.1 基础动画配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// pages.json
{
"pages": [{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页",
"app-plus": {
"animationType": "slide-in-right",
"animationDuration": 300
}
}
}]
}

// 页面跳转时指定动画
uni.navigateTo({
url: '/pages/detail/detail',
animationType: 'slide-in-bottom',
animationDuration: 300
})

4.2 自定义转场动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<!-- components/page-transition.vue -->
<template>
<view class="page-transition" :class="[transitionClass]">
<slot></slot>
</view>
</template>

<script>
export default {
data() {
return {
transitionClass: ''
}
},
methods: {
enter() {
this.transitionClass = 'slide-enter'
setTimeout(() => {
this.transitionClass = 'slide-enter-active'
}, 50)
},
leave() {
this.transitionClass = 'slide-leave'
setTimeout(() => {
this.transitionClass = 'slide-leave-active'
}, 50)
}
}
}
</script>

<style>
.page-transition {
position: absolute;
width: 100%;
height: 100%;
transition: all 0.3s ease;
}

.slide-enter {
transform: translateX(100%);
}
.slide-enter-active {
transform: translateX(0);
}
.slide-leave {
transform: translateX(0);
}
.slide-leave-active {
transform: translateX(-100%);
}
</style>

5. 常见问题与解决方案

5.1 页面栈溢出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 检查页面栈深度
function checkPageStack() {
const pages = getCurrentPages()
const maxStack = 10 // 最大页面栈深度

if (pages.length >= maxStack) {
uni.showModal({
title: '提示',
content: '页面层级过深,是否返回首页?',
success: (res) => {
if (res.confirm) {
uni.reLaunch({
url: '/pages/index/index'
})
}
}
})
return false
}
return true
}

// 使用示例
methods: {
navigateToDetail() {
if (!checkPageStack()) return
uni.navigateTo({
url: '/pages/detail/detail'
})
}
}

5.2 参数长度限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 处理长参数传递
function handleLongParams(params) {
if (typeof params !== 'string') {
params = JSON.stringify(params)
}

// 检查参数长度
if (params.length > 2048) {
// 存储到本地
const key = 'temp_params_' + Date.now()
uni.setStorageSync(key, params)
return key
}

return params
}

// 页面A:传递参数
const params = handleLongParams(this.longData)
uni.navigateTo({
url: `/pages/detail/detail?key=${params}`
})

// 页面B:接收参数
onLoad(options) {
let data = options.key
if (data.startsWith('temp_params_')) {
// 从本地存储获取
data = uni.getStorageSync(data)
// 清理存储
uni.removeStorageSync(data)
}
this.handleData(JSON.parse(data))
}

6. 最佳实践建议

  1. 合理使用页面跳转方式
  2. 实现统一的路由拦截
  3. 注意页面栈管理
  4. 优化转场动画
  5. 处理异常情况

7. 总结

  1. 掌握基础路由方法
  2. 实现权限控制
  3. 处理页面通信
  4. 优化用户体验
  5. 解决常见问题

如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力!

上一篇 uni-app状态管理进阶:Vuex最佳实践与性能优化
下一篇 uni-app性能优化实战:从加载到渲染的全方位提升
感谢您的支持!
微信赞赏码 微信赞赏
支付宝赞赏码 支付宝赞赏