1.2.3 • Published 2 years ago

u-vue-router-intercept v1.2.3

Weekly downloads
-
License
-
Repository
-
Last release
2 years ago

@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')

常见场景

一个应用有如下需求

  1. 加载任意功能页面前,需要获取用户名展示
  2. 加载任意功能页面,需要获取权限,来确认是否能够进入
  3. 存在白名单路由,该页面即使无权限,无用户信息都可以自由进入
  4. 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次拉取用户信息、用户权限接口,虽然两个路由拦截配置是相同的,而且可以任意调换函数执行顺序

其他

作者:基础建设组-金麦郎