1. 路由过滤器想法
路由过滤器的想法来源于后台的过滤器想法,后台会将到前端发起的一个个的请求,进入到一个个的过滤器中,只有当过滤器中的一些比如是否登录、是否具有相关权限的校验通过后,才会放行这个过滤器。对于前端来说,所有的路由都需要经过router.beforeEach这个统一的路由拦截方法,我想在前端通过像后端编写过滤器的方式,来对前端路由做一定的控制。
这样做一个是能够简化代码,让代码逻辑更加清晰易懂,不会出现逻辑混合在一起的情况,再有就是可以职责分离,每一个过滤器都只负责自己需要校验的功能。最后是便于追踪,可以清楚的知道页面是在那一个过滤器中出现的问题,便于调试和定位代码。
2. 路由过滤器的实现
- 我首先定义了一个统一的过滤器类,通过继承和复写的方式来实现过滤器子类。这也是面向对象通常使用的方式吧,虽然js好的实现方式可能是组合而非继承
export default class BaseFilter {
// 主要的过滤器方法
async filter(to, from) {
}
// 过滤器名字
getName() {
throw new Error('必须要覆写此方法')
}
// 过滤器排序
order() {
return 1
}
}
- 通过实现判断用户是否登录,如果用户未登录则跳转首页的过滤器
import BaseFilter from './baseFilter'
export default class LoginFilter extends BaseFilter {
async filter(to, from) {
// 判断路由是否需要校验登录
if (!to.meta.requireLogin) {
return null
}
// 如果用户未登录则直接返回一个新的路由地址,跳转首页
if (store.state.user.isLogin !== true) {
return {
path: '/',
query: { referrer: to.fullPath }
}
}
}
getName() {
return 'LoginFilter'
}
}
- 通过返回一个filterHandler方法来组合实现路由过滤
const files = require.context('.', false, /\.js$/)
// 过滤器实例化类数组
const ORIGINAL_FILTER_LIST = []
// 导入所有过滤器
files.keys().forEach(key => {
if (key === './index.js' || key === './baseFilter.js') return
const Clazz = files(key).default
ORIGINAL_FILTER_LIST.push(new Clazz())
})
// 依次校验过滤器
export default async function filterHandler(to, from) {
// 调整过滤器先后顺序
ORIGINAL_FILTER_LIST = ORIGINAL_FILTER_LIST.sort((a, b) => {
return b.order() - a.order()
})
let handlerResult = null
let lastIndex = 99999
console.groupCollapsed('路由FILTER')
console.log('------------------------ FILTER START ------------------------')
for (let i = 0; i < ORIGINAL_FILTER_LIST.length; i++) {
const filterChainListElement = ORIGINAL_FILTER_LIST[i]
const filterResult = await filterChainListElement.filter(to, from)
if (handlerResult == null && filterResult != null) {
handlerResult = filterResult
lastIndex = i
}
if (i < lastIndex) {
console.log('- ' + ORIGINAL_FILTER_LIST[i].getName() + '%c [通过]', 'color:#0f0;')
} else if (i === lastIndex) {
console.log('- ' + ORIGINAL_FILTER_LIST[i].getName() + '%c [失败]', 'color:#f00;')
} else {
console.log('- ' + ORIGINAL_FILTER_LIST[i].getName() + '%c [未进入]', 'color:#abc;')
}
}
console.log('------------------------ FILTER END ------------------------')
console.groupEnd()
return handlerResult
}
- 最后在router.beforeEach中调用filterHandler
import filterHandler from './filter'
router.beforeEach(async(to, from, next) => {
const filterResult = await filterHandler(to, from, next, filterList)
if (filterResult != null) {
next(filterResult)
} else {
next()
}
})
这样路由过滤器的改造就完成了