1.2.3 • Published 2 years ago
u-vue-router-intercept v1.2.3
@weier/u-vue-router-intercept
- 基于compose实现路由拦截,方便精细化处理vue项目中复杂路由拦截规则
- 开发者只需要定于不同的 路由拦截函数,插件会自动按先后顺序处理路由拦截
next()
与next(route)
是有区别的:next函数接收到参数会执行vueRouter.next(route)
并且跳出拦截流程前往执行目标路由拦截流程;不接收参数时 会执行下一个拦截函数
// 安装
npm i @weier/u-vue-router-intercept -S
routerIntercept 示例
import routerIntercept from '@weier/u-vue-router-intercept' // 用法
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
let hasLogined = false
let promissions = []
const checkLogin = async ({to, from, next, router}) => {
if (!hasLogined) {
try {
await request('login')
checkLogin = true
// 进入下一流程
next()
} catch(e) {
// 跳出拦截&不会执行下一个拦截函数,前往目标路由
next('/login')
}
} else {
// 进入下一流程
next()
}
}
const getPromission = async ({to, from, next, router}) => {
if (promissions.length === 0) {
await request('promissions')
promissions = ['/admin']
// 进入下一流程 可能是router.next or 下一个逻辑
next()
} else {
next()
}
}
const checkPromission = ({to, from, next, router}) => {
if (promissions.includes(to.path)) {
// 进入下一流程
next()
} else {
next('/403')
}
}
const router = {
mode: 'hash',
routes: [
{
path: '/',
components: null,
meta: {
intercepts: [checkLogin, getPromission, checkPromission],
}
}
]
}
routerIntercept(router, [checkLogin])
路由权限控制示例
// src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import api37919 from '@/api/interface/project93/api37919' // 菜单接口
import api38808 from '@/api/interface/project93/api38808' // 组织接口
import { useRouter, createMenuInterceptFn, getPermissionsIntercept, createUserInterceptFn } from '@weier/u-vue-router-intercept'
import { routes } from '@/router/config'
export const { router } = useRouter(Vue, VueRouter)({
routes, // 路由表
iconClassName: 'icon-menu', // icon指定的前缀 默认icon-menu
closeGlobalRedirect: false, // 自动添加 {path: '*',redirect: { path: '/404' }}
useMock: WEIER.isMock, // 是否使用mock模式
defaultIntercept: (params) => { // 默认路由拦截器 meta.intercepts为undefined
// createMenuInterceptFn, getPermissionsIntercept, createUserInterceptFn 内置方法
return [createUserInterceptFn(api38808, '@@OrgId')(params), createMenuInterceptFn(api37919)(params), getPermissionsIntercept(params)]
}
})
// src/router/config.js
import Layout from '@/components/layout'
/**
* 需要权限验证的路由
* meta:{
* title: 'title' breadcrumb或菜单名称
* icon: 'iconfont-class-name' 默认图标
* breadcrumb: false 是否面包屑
* isMenu: false 是否菜单
* intercepts: [] 路由拦截器
* }
*/
export const routes = [{
path: '/',
component: Layout,
// Layout组件props接收了 routeStore 包含 menus、selectOrg 两个observable属性
// Layout组件可 通过包的两个方法 getActiveMenu, getBreadCrumbList 分别获取高亮和面包屑数据 自行组装使用
children: [
{
name: 'orders',
component: null, // 一级菜单可以不配置 component 也可以不配置path
meta: { title: '订单及回款管理', icon: 'el-icon-document-copy' },
children: [
{
meta: { title: '订单管理', breadcrumb: true },
path: '/orders/manage',
name: 'orderManage',
component: () => import('@/pages/orders/manage'),
children: [
{
meta: { title: '创建订单', breadcrumb: true, isMenu: false }, // 三级菜单 可以通过isMenu控制不展示
path: '/orders/action',
name: 'orderCreate',
component: OrderAction
},
{
meta: { title: '编辑订单', breadcrumb: true, isMenu: false },
path: '/orders/action/:id',
name: 'orderEdit',
component: OrderAction
},
]
},
{
meta: { title: '回款管理', breadcrumb: true },
path: '/orders/outstanding',
name: 'orderOutstanding',
component: () => import('@/pages/orders/outstanding')
},
{
meta: { title: '退款管理', breadcrumb: true },
path: '/orders/refund',
name: 'orderRefund',
component: () => import('@/pages/orders/refund')
},
]
}
]
}]
// src/main.js
import Vue from 'vue'
import App from './App'
import { router } from './router'
/* eslint-disable no-new */
new Vue({
router,
render: h => h(App)
}).$mount('#app')
常见场景
一个应用有如下需求
- 加载任意功能页面前,需要获取用户名展示
- 加载任意功能页面,需要获取权限,来确认是否能够进入
- 存在白名单路由,该页面即使无权限,无用户信息都可以自由进入
- login一类的页面,如果用户信息能正常拉取,是不需要进入的,可以自动定向到 首页
分析以上需求,有一下伪代码
import { state, commit } from '@/store'
const getUserDetailOnce = async ({ to, from, next }) => {
const nextRoute = () => to.path === '/login' ? next('/home') : next()
if (!state.userDetail.name) {
try {
const { name } = await request('/user/detail')
commit('updateUserDetail', { name })
nextRoute()
} catch (e) {
// 无法正常获取用户信息的,需要重新登录
to.path !== '/login' ? next(`/login?redirectUri=${encodeURIComponent(window.location.href)}`) : next()
}
} else {
nextRoute()
}
}
// 获取权限
const getPremissionsOnce = async ({ next }) => {
if (!state.premissions) {
try {
const premissions = await request('/user/premissions')
commit('updatePremissions', premissions)
if (premissions.length > 0) {
next()
} else {
confirm('您似乎还没有权限,请联系管理员')
}
} catch (e) {
// 无法正常获取用户信息的,需要重新登录
next(`/login?redirectUri=${encodeURIComponent(window.location.href)}`)
}
} else {
next()
}
}
// 根据权限表校验权限
const checkPremission = ({to, next}) => {
// 根据具体数据格式来校验
if (state.premissions.includes(to.path)) {
next()
} else {
next('/403')
}
}
const routes = [
{
path: '/home',
component: Home,
meta: {
intercepts: [
getUserDetailOnce,
getPremissionsOnce,
checkPremission,
]
}
},
{
path: '/about',
component: About,
meta: {
intercepts: [
getUserDetailOnce,
getPremissionsOnce,
checkPremission,
]
}
},
{
path: '/productDescription',
// 功能介绍页面,可以不拉取用户信息,权限
component: ProductDescription,
meta: {
intercepts: []
}
},
{
path: '/login',
// 如果能正常获取用户信息,应该直接切换到首页
component: Login,
meta: {
intercepts: [
getUserDetailOnce
]
}
}
]
以上流程,如果用户从 /home
切换到 /about
不会2次拉取用户信息、用户权限接口,虽然两个路由拦截配置是相同的,而且可以任意调换函数执行顺序