# u-vue-router-intercept

> erhai 前端组件库

Latest version **1.2.3** (published 2022-10-19) · 0 weekly downloads

## Install

```sh
npm install u-vue-router-intercept
pnpm add u-vue-router-intercept
yarn add u-vue-router-intercept
bun add u-vue-router-intercept
```

## Health

**Score 20/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities.

Warnings: low downloads; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.2.3 |
| Published | 2022-10-19 |
| First published | 2022-10-19 |
| Weekly downloads | 0 |
| TypeScript types | bundled |
| Module format | CommonJS |
| Node | >=8.9.1 |
| Dependencies | 1 |
| Unpacked size | 78.1 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Maintainers | fengye12 |

## Links

- npm: https://www.npmjs.com/package/u-vue-router-intercept
- npm.io page: https://npm.io/package/u-vue-router-intercept

## Dependencies (1)

- [vue-router](https://npm.io/package/vue-router.md) ^3.4.7

## Recent versions

- 1.2.3 (latest) — 2022-10-19

## README

# `@weier/u-vue-router-intercept`

* 基于compose实现路由拦截，方便精细化处理vue项目中复杂路由拦截规则
* 开发者只需要定于不同的 路由拦截函数，插件会自动按先后顺序处理路由拦截
> `next()` 与 `next(route)` 是有区别的：next函数接收到参数会执行`vueRouter.next(route)`并且跳出拦截流程前往执行目标路由拦截流程；不接收参数时 会执行下一个拦截函数

```js
// 安装
npm i @weier/u-vue-router-intercept -S

```
routerIntercept 示例
```js
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])

```

路由权限控制示例
```js
// 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一类的页面，如果用户信息能正常拉取，是不需要进入的，可以自动定向到 首页

分析以上需求，有一下伪代码

```js
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次拉取用户信息、用户权限接口，虽然两个路由拦截配置是相同的，而且可以任意调换函数执行顺序

## 其他
> [作者：基础建设组-金麦郎](dingtalk://dingtalkclient/action/sendmsg?dingtalk_id=venus1st)

---
_Source: https://npm.io/package/u-vue-router-intercept · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
