1. 程式人生 > 程式設計 >vue-router 基於後端permissions動態生成導航選單的示例程式碼

vue-router 基於後端permissions動態生成導航選單的示例程式碼

目錄
  • .
  • 1、註冊全域性守衛
  • 2、Vuex狀態管理 全域性快取routes
  • 3、路由攔截
  • 4、路由選單
  • 5、遞迴選單vue元件

Vue.js

  • vue-router
  • vuex

1、註冊全域性守衛

核心邏輯
1、token身份驗證(後端) => token失效返回登入頁面
2、獲取使用者許可權
3、校驗permissions,動態新增路由選單

router.beforeResolve 註冊一個全域性守衛。和 router.beforeEach 類似,區別是在導航被確認之前,同時在所有元件內守衛和非同步路由元件被解析之後,解析守衛就被呼叫。

router.beforeResolve(async (to,from,next) => {
  let hasToken = store.getters['User/accessToken']
  if (!settings.loginInterception) hasToken = true
  if (hasToken) {
    if (to.path === '/auth/sign-in') {
      next({ path: '/' })
    } else {
      const hasPermissions =
        store.getters['User/permissions'] &&
        store.getters['User/permissions'].length > 0
      if (hasPermissions) {
        next()
      } else {
        try {
          let permissions
          if (!constant.loginInterception) {
            // settings.js loginInterception為false時,建立虛擬許可權
            await store.dispatch('User/setPermissions',['admin'])
            permissions = ['admin']
          } else {
            permissions = await store.dispatch('User/getUserInfo')
          }
          let accessRoutes = []
          accessRoutes = await store.dispatch('Routes/setRoutes',permissions)
          // 新增路由
          router.addRoutes(accessRoutes)
          next({ ...to,replace: true })
        } catch {
          await store.dispatch('User/resetAccessToken')
        }
      }
    }
  } else {
    if (settings.routesWhiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next('/auth/sign-in')
    }
  }
  document.title = getPageTitle(to.meta.title)
})

settings.js 全域性設定

export default {
  // 是否開啟登入攔截
  loginInterception: true,// 不經過token校驗的路由
  routesWhiteList: ['/auth/sign-in','/auth/register','/401','/404'],}

2、Vuex狀態管理 全域性快取routes

  • state :對資料的全域性儲存
  • getter: 可以理解為computed ,對資料進行計算
  • mutations :對資料的同步更改
  • actions:對資料的非同步更改(實現非同步操作)
  • module: 將 store 分割成模組
/**
 * @author Alan
 * @description 路由攔截狀態管理
 */
import { asyncRoutes,constantRoutes } from '@/router'
import { filterAsyncRoutes } from '@/Utils/handleRoutes'

const state = () => ({
  routes: [],partialRoutes: []
})
const getters = {
  routes: (state) => state.routes,partialRoutes: (state) => state.partialRoutes
}
const mutations = {
  setRoutes (state,routes) {
    state.routes = constantRoutes.concat(routes)
  },setPartialRoutes (state,routes) {
    state.partialRoutes = constantRoutes.concat(routes)
  }
}
const actions = {
  async setRoutes ({ commit },permissions) {
    const finallyAsyncRoutes = await filterAsyncRoutes(
      [...asyncRoutes],permissions
    )
    commit('setRoutes',finallyAsyncRoutes)
    return finallyAsyncRoutes
  },setPartialRoutes ({ commit },accessRoutes) {
    commit('setPartialRoutes',accessRoutes)
    return accessRoutes
  }
}
export default { namespaced: true,state,getters,mutations,actions }

3、路由攔截

/**
 * @author Alan
 * @description 判斷當前路由是否包含許可權
 * @param permissions
 * @param route
 * @returns {boolean|*}
 */
export function hasPermission (permissions,route) {
  if (route.meta && route.meta.permissions) {
    return permissions.some((role) => route.meta.permissions.includes(role))
  } else {
    return true
  }
}

/**
 * @author Alan
 * @description 根據permissions陣列攔截路由
 * @param routes
 * @param permissions
 * @returns {[]}
 */
export function filterAsyncRoutes (routes,permissions) {
  const finallyRoutes = []
  routes.forEach((route) => {
    const item = { ...route }
    if (hasPermission(permissions,item)) {
      if (item.children) {
        item.children = filterAsyncRoutes(item.children,permissions)
      }
      finallyRoutes.push(item)
    }
  })
  return finallyRoutes
}

4、路由選單

/*
* @author Alan
* @description 公共路由
*/
export const constantRoutes = [
  {
    path: '/auth',name: 'auth1',component: AuthLayout,children: authChildRoutes('auth1'),hidden: true // 隱藏選單
  },{
    path: '/',name: 'dashboard',component: VerticleLayout,meta: {
      title: 'Dashboard',name: 'sidebar.dashboard',is_heading: false,is_active: false,link: '',class_name: '',is_icon_class: true,icon: 'ri-home-4-line',permissions: ['admin']
    },children: childRoutes('dashboard')
  }
]

/*
* @author Alan
* @description 非同步路由
*/
export const asyncRoutes = [
  {
    path: '/menu-design',name: 'horizontal-dashboard',component: HorizantalLayout,meta: {
      title: 'Menu Design',name: 'sidebar.MenuDesign',icon: 'ri-menu-3-line',children: horizontalRoute('dashboard')
  },{
    path: '/core',name: 'core',meta: {
      title: 'UI Elements',name: 'sidebar.uiElements',icon: 'ri-pDEqEbQCpencil-ruler-line',permissions: ['admin']
   DEqEbQCp },children: coreChildRoute('core')
  }
]

5、遞迴選單vue元件

<template>
  <b-collapse tag="ul" :claDEqEbQCpss="className" :visible="open" :id="idName" :accordion="accordianName">
    <li v-for="(item,index) in items" :key="index" :class=" !hideListMenuTitle? 'p-0' : item.meta.is_heading ? 'iq-menu-title' :activeLink(item) && item.children ? 'active' : activeLink(item) ? 'active' : ''">
      <template v-if="!item.hidden">
        <i v-if="item.meta.is_heading && hideListMenuTitle" class="ri-subtract-line" />
        <span v-if="item.meta.is_heading && hideListMenuTitle">{{ $t(item.meta.name) }}</span>
        <router-link :to="item.meta.link" v-if="!item.is_heading" :class="`iq-waves-effect ${activeLink(item) && item.children ? 'active' : activeLink(item) ? 'active' : ''}`" v-b-toggle="item.meta.name">
          <i :class="item.meta.icon" v-if="item.meta.is_icon_class"/>
          <template v-else v-html="item.meta.icon">
          </template>
          <span>{{ $t(item.meta.name) }}</span>
          <i v-if="item.children" class="ri-arrow-right-s-line iq-arrow-right" />
          <small v-html="item.meta.append" v-if="hideListMenuTitle" :class="item.meta.append_class" />
        </router-link>
        <List v-if="item.children" :items="item.children" :sidebarGroupTitle="hideListMenuTitle" :open="item.meta.link.name !== '' && activeLink(item) && item.children ? true : !!(item.meta.link.name !== '' && activeLink(item))" :idName="item.meta.name" :accordianName="`sidebar-accordion-${item.meta.class_name}`" :className="`iq-submenu ${item.meta.class_name}`" />
      </template>
    </li>
  </b-collapse>
</template>
<script>
import List from './CollapseMenu' // 自身元件
import { core } from '../../../config/pluginInit'
export default {
  name: 'List',props: {
    items: Array,className: { type: String,default: 'iq-menu' },open: { type: Boolean,default: false },idName: { type: String,default: 'sidebar' },accordianName: { type: String,sidebarGroupTitle: { type: Boolean,default: true }
  },components: {
    List
  },computed: {
    hideListMenuTitle () {
      return this.sidebarGroupTitle
    }
  },mounted () {
  },methods: {
    activeLink (item) {
      return core.getActiveLink(item,this.$route.name)
    }
  }
}
</script>

到此這篇關於vue-router 基於後端permissions動態生成導航選單的示例程式碼的文章就介紹到這了,更多相關vue-router permissions導航選單內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!