惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
N
News and Events Feed by Topic
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
The Cloudflare Blog
H
Heimdal Security Blog
Schneier on Security
Schneier on Security
Engineering at Meta
Engineering at Meta
Google Online Security Blog
Google Online Security Blog
宝玉的分享
宝玉的分享
AI
AI
The GitHub Blog
The GitHub Blog
MongoDB | Blog
MongoDB | Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
The Last Watchdog
The Last Watchdog
T
Troy Hunt's Blog
S
Security @ Cisco Blogs
H
Hacker News: Front Page
F
Fortinet All Blogs
博客园_首页
S
Secure Thoughts
N
News and Events Feed by Topic
P
Proofpoint News Feed
Microsoft Azure Blog
Microsoft Azure Blog
I
InfoQ
Spread Privacy
Spread Privacy
Hacker News - Newest:
Hacker News - Newest: "LLM"
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Hugging Face - Blog
Hugging Face - Blog
Hacker News: Ask HN
Hacker News: Ask HN
C
CXSECURITY Database RSS Feed - CXSecurity.com
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
L
LINUX DO - 最新话题
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Schneier on Security
Know Your Adversary
Know Your Adversary
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Scott Helme
Scott Helme
P
Privacy & Cybersecurity Law Blog
S
Securelist
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
O
OpenAI News
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
PCI Perspectives
PCI Perspectives
L
LangChain Blog
雷峰网
雷峰网
Security Archives - TechRepublic
Security Archives - TechRepublic
V2EX - 技术
V2EX - 技术

吖远zzyの博客

解决华为开发者工具 DevEco Studio 登录跳转 localhost:10101 端口被阻止问题 | 吖远zzyの博客 微信小程序个人资质审核血泪史:踩坑,从反复被拒到神奇过审 | 吖远zzyの博客 如何实现公众号自动回复或做一个短视频无水印解析机器人? | 吖远zzyの博客 以后在手机上用 Termux 和 GitHub Actions 更新 Hexo 博客 | 吖远zzyの博客 必备!这款万能小程序能给抖音/豆包视频图集去除水印、还有有趣的测反应、玩成语模拟工具。 自制的一些免费API接口第二弹(获取QQ昵称、头像、抖音/豆包视频去水印等...) 告别原生导航栏:微信小程序自定义导航栏完美适配方案 在安卓手机上运行OpenClaw?当然可以,用Termux折腾OpenClaw安装QQ机器人的踩坑记录... | 吖远zzyの博客 个人开发工具之抖音直播录制工具:一款功能强大的Android直播录制应用 UniApp中Canvas绘图的易错点与踩坑指南 QQ频道机器人与UniApp开发:常见踩坑点与解决方案 UniApp中Canvas绘图不显示的常见问题与解决方案 Hexo博客实现随机文章功能的完整教程 QQ频道机器人Android客户端使用指南 | 吖远zzyの博客 安卓版QQ频道机器人APP客户端插件开发指南 | 吖远zzyの博客 2024年AI编程助手深度评测:哪款最适合你? uni-app地图定位踩坑记:地图功能和定位的那些坑 uni-app文件上传踩坑记:图片处理和上传全攻略 uni-app表单验证踩坑记:这些坑我替你踩过了 uni-app开发踩坑记录:新手必看的常见问题与解决方案 uni-app安全防护指南:构建可靠的跨端应用 uni-app性能优化指南:从加载到渲染的全方位提升 uni-app动画效果实战:从基础到高级的动画实现指南 uni-app组件开发实战:从基础到进阶的最佳实践 uni-app网络请求与缓存策略:构建高效的数据层 uni-app状态管理进阶:Vuex最佳实践与性能优化
uni-app路由与页面跳转:最佳实践与踩坑指南
吖远zzy · 2024-03-15 · via 吖远zzyの博客
  1. 1. 1. 基础路由方法
    1. 1.1. 1.1 页面跳转方式
    2. 1.2. 1.2 参数传递
  2. 2. 2. 路由拦截与权限控制
    1. 2.1. 2.1 全局路由拦截
    2. 2.2. 2.2 页面级权限控制
  3. 3. 3. 页面通信方案
    1. 3.1. 3.1 页面间事件通信
    2. 3.2. 3.2 页面栈管理
  4. 4. 4. 路由动画与转场效果
    1. 4.1. 4.1 基础动画配置
    2. 4.2. 4.2 自定义转场动画
  5. 5. 5. 常见问题与解决方案
    1. 5.1. 5.1 页面栈溢出
    2. 5.2. 5.2 参数长度限制
  6. 6. 6. 最佳实践建议
  7. 7. 7. 总结

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. 解决常见问题

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