在使用uni-app开发多端应用时,我们有时需要在路由跳转前执行一些操作。这种需求在浏览器中的方案已经很成熟了,Vue和React都有自己的路由管理工具,可以通过路由守卫实现,而在 uni-app开发原生应用时,可以借助 uni.addInterceptor
来模拟类似功能。
分享一个封装好的简易路由拦截器模块,支持统一拦截多个路由方法或单独拦截指定方法,并且支持拦截逻辑的自定义扩展。
🧩 使用场景
- 页面跳转前确认是否保存更改
- 用户未登录时禁止跳转到某些页面
- 某些页面禁止后退操作
- 记录页面跳转日志
📦 方法
封装后的模块 RouterInterceptor
提供以下两个主要方法:
init(callback)
:初始化全局拦截器,拦截navigateTo
、redirectTo
、navigateBack
、switchTab
、reLaunch
五个常用方法。initForMethod(method, callback)
:只拦截某个指定方法。
📄 源码解析
下面是完整的实现代码:
js
/**
* 简单的路由拦截器
* 每次使用时实时创建拦截器
* ps: 下面的$Log和$LogError是个人封装的log方法
*/
const RouterInterceptor = {
init(callback) {
if (typeof callback !== 'function') {
$LogError('RouterInterceptor Init Error', '回调必须是函数')
return { remove: () => {} }
}
const routeMethods = ['navigateTo', 'redirectTo', 'navigateBack', 'switchTab', 'reLaunch']
routeMethods.forEach(method => {
uni.addInterceptor(method, {
invoke: args => {
const pages = getCurrentPages()
const currentPage = pages.length > 0 ? pages[pages.length - 1] : null
const fromRoute = currentPage ? currentPage.route : ''
const toUrl = method === 'navigateBack' ? (pages.length > 1 ? pages[pages.length - 2].route : '') : args.url || ''
const result = callback(fromRoute, toUrl, method, args)
if (result === false) {
$Log('RouterInterceptor', `路由被拦截: ${method}`)
return false
}
if (result && typeof result === 'object') {
return result
}
return args
}
})
})
return {
remove: () => {
routeMethods.forEach(method => {
uni.removeInterceptor(method)
})
$Log('RouterInterceptor', '所有拦截器已移除')
}
}
},
initForMethod(method, callback) {
if (typeof callback !== 'function') {
$LogError('', '回调必须是函数')
return { remove: () => {} }
}
uni.addInterceptor(method, {
invoke: args => {
const result = callback(args)
if (result === false) {
$Log('RouterInterceptor', `路由被拦截: ${method}`)
return false
}
if (result && typeof result === 'object') {
return result
}
return args
}
})
return {
remove: () => {
uni.removeInterceptor(method)
$Log('RouterInterceptor', `${method} 拦截器已移除`)
}
}
}
}
export default RouterInterceptor
🛠️ 使用示例
1. 拦截 navigateBack:防止误返回未保存页面
javascript
js
复制编辑
const interceptor = RouterInterceptor.initForMethod('navigateBack', (args) => {
const hasUnsavedChanges = true // 可从状态管理中获取
if (hasUnsavedChanges) {
uni.showModal({
title: '提示',
content: '你有未保存的修改,确定要离开吗?',
success: res => {
if (res.confirm) {
uni.navigateBack(args)
}
}
})
return false
}
return args
})
2. 移除拦截器
csharp
js
// 假设之前保存的返回值是 interceptor
interceptor.remove()