欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

前端配合后端實(shí)現(xiàn)Vue路由權(quán)限的方法實(shí)例

 更新時(shí)間:2022年05月12日 10:43:30   作者:liy1wen  
一開始我還以為vue的路由只能用在工程化的項(xiàng)目里面,其實(shí)不然,下面這篇文章主要給大家介紹了關(guān)于前端配合后端實(shí)現(xiàn)Vue路由權(quán)限的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

在開發(fā)管理后臺(tái)時(shí),都會(huì)存在多個(gè)角色登錄,登錄成功后,不同的角色會(huì)展示不同的菜單路由。這就是我們通常所說(shuō)的動(dòng)態(tài)路由權(quán)限,實(shí)現(xiàn)路由權(quán)限的方案有多種,比較常用的是由前端使用addRoutes(V3版本改成了addRoute)動(dòng)態(tài)掛載路由和服務(wù)端返回可訪問的路由菜單這兩種。上一篇文章講了純前端實(shí)現(xiàn)路由權(quán)限,沒看過的可以點(diǎn)擊文章鏈接純前端實(shí)現(xiàn)Vue路由權(quán)限。今天主要是基于后端返回路由菜單的基礎(chǔ)上,實(shí)現(xiàn)路由權(quán)限功能。

實(shí)現(xiàn)思路

后端返回路由菜單主要是在我們登錄之后,后端接口會(huì)直接返回當(dāng)前用戶可訪問的完整路由菜單,相當(dāng)于前端基于RBAC模型篩選出了前端可訪問的路由列表。

需要注意的是,后端返回的路由菜單是不包括login、404等頁(yè)面的。前端這邊還是需要寫一份完整的路由列表,基于后端返回的可訪問路由菜單去篩選出需要掛載在router上的路由列表。

代碼實(shí)現(xiàn)

登錄

首先是登錄,登錄成功后,服務(wù)端會(huì)返回登錄用戶可訪問的路由菜單userMenus,我們一般會(huì)將這些信息保存到Vuex里。

登錄方法:

const login = () => {
  ruleFormRef.value?.validate((valid: boolean) => {
    if (valid) {
      store.dispatch('userModule/login', { ...accountForm })
    } else {
      console.log('error submit!')
    }
  })
}

Vuex對(duì)應(yīng)異步操作:

async login({ commit }, payload: IRequest) {
  // 登錄獲取token
  const { data } = await accountLogin(payload)
  commit('SET_TOKEN', data.token)
  localCache.setCache('token', data.token)
  // 獲取用戶信息
  const userInfo = await getUserInfo(data.id)
  commit('SET_USERINFO', userInfo.data)
  localCache.setCache('userInfo', userInfo.data)
  // 獲取菜單
  const userMenu = await getUserMenu(userInfo.data.role.id)
  commit('SET_USERMENU', userMenu.data)
  localCache.setCache('userMenu', userMenu.data)
  router.replace('/main/analysis/dashboard')
},

接口返回的路由菜單信息:

路由菜單

可以看到,返回的userMenus是一個(gè)數(shù)組,包含了圖標(biāo)icon、路由名稱name、路由地址、子路由children、路由type等重要信息。前面這些信息主要是用于遍歷生成頁(yè)面左側(cè)的菜單列表,路由type則是用于后面篩選出需要掛載在router上的路由列表。

本地路由列表

前端這邊還是需要寫一份完整的路由列表,我這里打算在router/index.ts里面寫入接口不返回的菜單,如login、404等頁(yè)面。將接口可能返回的菜單單獨(dú)放在router/main下面。

router/index.ts:

import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
const routes: RouteRecordRaw[] = [
  {
    path: '/',
    redirect: '/main'
  },
  {
    path: '/login',
    name: 'login',
    component: () => import('@/views/login/index.vue'),
    meta: {
      title: '登錄'
    }
  },
  {
    path: '/main',
    name: 'main',
    redirect: '/main/analysis/dashboard',
    component: () => import('@/views/main/index.vue'),
    meta: {
      title: '核心技術(shù)'
    }
  },
  {
    path: '/:pathMatch(.*)*',
    name: 'notFound',
    component: () => import('@/views/404.vue'),
    meta: {
      title: '頁(yè)面找不到~'
    }
  }
]

router/main下面就是寫入所有菜單列表:

單個(gè)菜單內(nèi)容,如dashboard.ts:

const dashboard = () => import('@/views/main/analysis/dashboard/dashboard.vue')
export default {
  path: '/main/analysis/dashboard',
  name: 'dashboard',
  component: dashboard,
  meta: {
    title: '商品統(tǒng)計(jì)'
  },
  children: []
}

整個(gè)router目錄:

router目錄

接下來(lái),我們就需要根據(jù)userMenus去過濾我們寫好的router/main下面的路由,也就是接口返回的菜單列表對(duì)應(yīng)一份路由列表,然后將路由列表掛載在router上,這樣就能訪問路由了。

生成路由

現(xiàn)在我們需要根據(jù)userMenus生成對(duì)應(yīng)的路由。

首先我們需要去加載所有的路由,也就是router/main下面的路由文件內(nèi)容。這里我使用的是require.context方法來(lái)加載所有的路由。

這里簡(jiǎn)單介紹下require.context這個(gè)api:

require.context 是webpack的一個(gè)api,通過執(zhí)行require.context()函數(shù),來(lái)獲取指定的文件夾內(nèi)的特定文件,在需要多次從同一個(gè)文件夾內(nèi)導(dǎo)入的模塊,使用這個(gè)函數(shù)可以自動(dòng)導(dǎo)入,不用每個(gè)都顯示的寫import來(lái)引入。

require.context(directory,useSubdirectories,regExp) 需要的參數(shù):

  • directory:要搜索文件的相對(duì)路徑
  • useSubdirectories:是否查詢其子目錄
  • regExp:匹配基礎(chǔ)組件文件名的正則表達(dá)式

我們就通過這個(gè)api來(lái)加載router/main下面的路由。

const routeFiles = require.context('../router/main', true, /.ts/)

我們對(duì)routeFiles進(jìn)行打?。?/p>

routeFiles

得到了一個(gè)對(duì)象,我們需要對(duì)這個(gè)對(duì)象進(jìn)行遍歷拿到文件內(nèi)容:

routeFiles.keys().forEach((key) => {
  const route = require('../router/main' + key.split('.')[1]).default
  console.log(route)
  allRoutes.push(route)
})

打印得到route

route

這樣我們就得到了所有的路由,放在allRoutes里面。

接下來(lái)我們需要根據(jù)userMenus獲取需要添加的routes。

開始我們提到過路由type,這個(gè)字段主要是區(qū)分菜單下是否還有子菜單,1表示有子菜單,2表示沒有子菜單。

接口返回的菜單

我們將allRoutes進(jìn)行遍歷,然后根據(jù)path與接口返回的菜單列表userMenus里的path進(jìn)行比較,如果相同就是匹配到了,那我們就需要這條路由,否則就將這條路由過濾掉。由于allRoutes下的每一項(xiàng)都還可能存在子路由,所以這里我們也需要進(jìn)行遞歸篩選。具體的方法如下:

const _recurseGetRoute = (menus: any[]) => {
  for (const menu of menus) {
    if (menu.type === 2) {
      const route = allRoutes.find((route) => route.path === menu.url)
      if (route) routes.push(route)
    } else {
      _recurseGetRoute(menu.children)
    }
  }
}

最終,routes就是我們得到的userMenus所對(duì)應(yīng)的路由列表。

將生成對(duì)應(yīng)的路由的邏輯整理如下:

import { RouteRecordRaw } from 'vue-router'

export function generateRoutes(userMenus: any[]): RouteRecordRaw[] {
  const routes: RouteRecordRaw[] = []
  // 1.先去加載默認(rèn)所有的routes
  const allRoutes: RouteRecordRaw[] = []
  const routeFiles = require.context('../router/main', true, /.ts/)
  routeFiles.keys().forEach((key) => {
    const route = require('../router/main' + key.split('.')[1]).default
    console.log(route)
    allRoutes.push(route)
  })
  // 2.根據(jù)菜單獲取需要添加的routes
  // userMenus:
  // type === 1 -> children -> type === 1
  // type === 2 -> url -> route
  const _recurseGetRoute = (menus: any[]) => {
    for (const menu of menus) {
      if (menu.type === 2) {
        const route = allRoutes.find((route) => route.path === menu.url)
        if (route) routes.push(route)
      } else {
        _recurseGetRoute(menu.children)
      }
    }
  }
  _recurseGetRoute(userMenus)
  return routes
}

掛載路由

最后,需要將我們得到的routes掛載er上面。

還是將掛載路由的時(shí)機(jī)放在全局路由守衛(wèi)這里,我們?cè)趓outer文件夾下創(chuàng)建一個(gè)permission.ts,用于寫全局路由守衛(wèi)相關(guān)邏輯:

import router from '@/router'
import { RouteLocationNormalized } from 'vue-router'
import localCache from '@/utils/cache'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import store from '@/store'

NProgress.configure({ showSpinner: false })
const whiteList = ['/login']
const userMenu = store.state.userModule.userMenu
router.beforeEach(
  async (
    to: RouteLocationNormalized,
    from: RouteLocationNormalized,
    next: any
  ) => {
    document.title = to.meta.title as string
    const token: string = localCache.getCache('token')
    NProgress.start()
    // 判斷該用戶是否登錄
    if (token) {
      if (to.path === '/login') {
        // 如果登錄,并準(zhǔn)備進(jìn)入 login 頁(yè)面,則重定向到主頁(yè)
        next({ path: '/' })
        NProgress.done()
      } else {
        store.dispatch('routesModule/generateRoutes', { userMenu })
        // 確保添加路由已完成
        // 設(shè)置 replace: true, 因此導(dǎo)航將不會(huì)留下歷史記錄
        next({ ...to, replace: true })
      }
    } else {
      // 如果沒有 token
      if (whiteList.includes(to.path)) {
        // 如果在免登錄的白名單中,則直接進(jìn)入
        next()
      } else {
        // 其他沒有訪問權(quán)限的頁(yè)面將被重定向到登錄頁(yè)面
        next('/login')
        NProgress.done()
      }
    }
  }
)
router.afterEach(() => {
  NProgress.done()
})

routesModule文件下的代碼:

// 引入generateRoutes
import { generateRoutes } from '@/utils/generateRoutes'
actions: {
  generateRoutes({ commit }, { userMenu }) {
    const routes = generateRoutes(userMenu)
    // 將routes => router.main.children
    routes.forEach((route) => {
      router.addRoute('main', route)
    })
  }
}

這樣,完整的路由權(quán)限功能就完成了。我們可以看一下頁(yè)面:

系統(tǒng)界面

總結(jié)

相比純前端實(shí)現(xiàn)路由權(quán)限,這種基于后端返回路由菜單的方式會(huì)顯得簡(jiǎn)單一些。我們不需要經(jīng)過RBAC去過濾出用戶可以訪問的路由,而是接口直接返回給了我們。我們只需要將路由菜單對(duì)應(yīng)生成一份路由,然后將路由進(jìn)行掛載。

到此這篇關(guān)于前端配合后端實(shí)現(xiàn)Vue路由權(quán)限的文章就介紹到這了,更多相關(guān)后端實(shí)現(xiàn)Vue路由權(quán)限內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue如何在main.js中配置全局的通用公共組件

    vue如何在main.js中配置全局的通用公共組件

    這篇文章主要介紹了vue如何在main.js中配置全局的通用公共組件問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • vue.js項(xiàng)目打包上線的圖文教程

    vue.js項(xiàng)目打包上線的圖文教程

    下面小編就為大家分享一篇vue.js項(xiàng)目打包上線的圖文教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2017-11-11
  • vuejs 制作背景淡入淡出切換動(dòng)畫的實(shí)例

    vuejs 制作背景淡入淡出切換動(dòng)畫的實(shí)例

    今天小編就為大家分享一篇vuejs 制作背景淡入淡出切換動(dòng)畫的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2018-09-09
  • 詳解Vue 單文件組件的三種寫法

    詳解Vue 單文件組件的三種寫法

    這篇文章主要介紹了詳解Vue 單文件組件的三種寫法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • 如何使用Webstorm和Chrome來(lái)調(diào)試Vue項(xiàng)目

    如何使用Webstorm和Chrome來(lái)調(diào)試Vue項(xiàng)目

    這篇文章主要介紹了如何使用Webstorm和Chrome來(lái)調(diào)試Vue項(xiàng)目,對(duì)Vue感興趣的同學(xué),一定要看一下
    2021-05-05
  • 詳解vue2和vue3如何定義響應(yīng)式數(shù)據(jù)

    詳解vue2和vue3如何定義響應(yīng)式數(shù)據(jù)

    這篇文章主要是來(lái)和大家一起討論一下vue2和vue3是如何定義響應(yīng)式數(shù)據(jù)的,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解下
    2023-11-11
  • Vue如何引用public中的js文件

    Vue如何引用public中的js文件

    這篇文章主要介紹了Vue如何引用public中的js文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • vue實(shí)現(xiàn)購(gòu)物車拋物線小球動(dòng)畫效果的方法詳解

    vue實(shí)現(xiàn)購(gòu)物車拋物線小球動(dòng)畫效果的方法詳解

    這篇文章主要介紹了vue實(shí)現(xiàn)購(gòu)物車拋物線小球動(dòng)畫效果的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了vue.js實(shí)現(xiàn)拋物線動(dòng)畫效果購(gòu)物車功能相關(guān)原理與操作注意事項(xiàng),需要的朋友可以參考下
    2019-02-02
  • vue引入高德地圖并繪制點(diǎn)線面的方法

    vue引入高德地圖并繪制點(diǎn)線面的方法

    這篇文章主要介紹了vue引入高德地圖并繪制點(diǎn)線面的實(shí)例代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2024-03-03
  • element?select必填項(xiàng)驗(yàn)證回顯問題的解決

    element?select必填項(xiàng)驗(yàn)證回顯問題的解決

    本文主要介紹了element?select必填項(xiàng)驗(yàn)證回顯問題的解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04

最新評(píng)論