vue項目 動態(tài)路由怎么做

vue項目實現(xiàn)動態(tài)路由的方式大體可分為兩種:

1.簡單的角色路由設(shè)置:比如只涉及到管理員和普通用戶的權(quán)限像屋。通常直接在前端進(jìn)行簡單的角色權(quán)限設(shè)置

前端這邊把路由寫好餐胀,登錄的時候根據(jù)用戶的角色權(quán)限來動態(tài)展示路由授艰,(前端控制路由)
詳情可參閱花褲衩大佬的項目手把手...

2.復(fù)雜的路由權(quán)限設(shè)置:比如OA系統(tǒng)胶哲、多種角色的權(quán)限配置体啰。通常需要后端返回路由列表,前端渲染使用

后臺傳來當(dāng)前用戶對應(yīng)權(quán)限的路由表卦方,前端通過調(diào)接口拿到后處理(后端處理路由)

這兩種方法各有優(yōu)點羊瘩,效果都能實現(xiàn)泰佳,我們公司是通過第二中種方法實現(xiàn)的盼砍,原因就是公司項目里有一個專門的用戶中心,里邊邏輯很復(fù)雜逝她,不好返給前端用戶權(quán)限浇坐,擔(dān)心路由放到前端不安全(以上的話是公司的后臺同學(xué)講的),那好吧黔宛,抱著都試試近刘、鍛煉下自己能力的態(tài)度,我們搞了第二種方法臀晃。

Vue 動態(tài)路由的實現(xiàn)(后臺傳遞路由觉渴,前端拿到并生成側(cè)邊欄)

思路整理

大體步驟:攔截路由->后臺取到路由->保存路由到localStorage(用戶登錄進(jìn)來只會從后臺取一次,其余都從本地取,所以用戶徽惋,只有退出在登錄路由才會更新)

后端管理創(chuàng)建菜單需要

菜單名字menName案淋;
菜單路徑menPath;
菜單指向的資源menuUrl(也就是組件地址, 一般從views層級開始寫)

前端登錄后通過接口請求拿到菜單數(shù)據(jù)后险绘,

將菜單數(shù)據(jù)轉(zhuǎn)換格式 轉(zhuǎn)成前端需要的路由表

menName ---> name
menPath ---> path
menuUrl ---->components文件

轉(zhuǎn)換時,用到這個方法找組件資源 把 menuUrl 可以變?yōu)閏omponents的格式踢京,轉(zhuǎn)為組件文件

module.exports = file => require('@/views' + file + '.vue').default // vue-loader at least v13.0.0+

生成路由表

可以再過濾一遍生成的路由表
下面這個方法找到views底下所有的組件資源

require.context('@/views', true, /\.vue$/).keys().forEach(v => map.set(v.replace(/^\.(.*)\.vue$/,'$1'), true))

export default map

路由表里路由的組件在所有組件資源里沒找到時,將該路由的path變?yōu)?404

過濾后宦棺,再動態(tài)添加

getRouter.push({ path: '*', redirect: '/404', hidden: true });
router.addRoutes(getRouter); //動態(tài)添加路由

代碼

前置工作:配置項目路由文件瓣距,該文件中沒有路由,或者存在一部分公共路由代咸,即沒有權(quán)限的路由

import Vue from 'vue'
import Router from 'vue-router'
import Layout from '@/layout';
Vue.use(Router)
// 配置項目中沒有涉及權(quán)限的公共路由
export const constantRoutes = [
    {
        path: '/login',
        component: () => import('@/views/login'),
        hidden: true
    },
    {
        path: '/404',
        component: () => import('@/views/404'),
        hidden: true
    },
]

const createRouter = () => new Router({
    mode: 'history',
    scrollBehavior: () => ({ y: 0 }),
    routes: constantRoutes
})
const router = createRouter()

export function resetRouter() {
    const newRouter = createRouter()
    router.matcher = newRouter.matcher
}

export default router

1.登錄后通過接口拿到后端返回的路由數(shù)據(jù)

每個路由都使用到組件Layout,這個組件是整體的頁面布局:左側(cè)菜單列蹈丸,右側(cè)頁面,所以children下邊的第一級路由就是你自己的開發(fā)的頁面,meta里包含著路由的名字,以及路由對應(yīng)的icon;
因為可能會有多級菜單呐芥,所以會出現(xiàn)children下邊嵌套children的情況;
路由是數(shù)組格式

后端返回的路由格式
"data": {
    "router": [
      {
        "path": "",
        "component": "Layout",
        "redirect": "dashboard",
        "children": [
          {
            "path": "dashboard",
            "component": "dashboard/index",  
            "meta": {
              "title": "首頁",
              "icon": "dashboard"
            }
          }
        ]
      },
      {
        "path": "/example",
        "component": "Layout",
        "redirect": "/example/table",
        "name": "Example",
        "meta": {
          "title": "案例",
          "icon": "example"
        },
        "children": [
          {
            "path": "table",
            "name": "Table",
            "component": "table/index",
            "meta": {
              "title": "表格",
              "icon": "table"
            }
          },
          {
            "path": "tree",
            "name": "Tree",
            "component": "tree/index",
            "meta": {
              "title": "樹形菜單",
              "icon": "tree"
            }
          }
        ]
      },
      {
        "path": "/form",
        "component": "Layout",
        "children": [
          {
            "path": "index",
            "name": "Form",
            "component": "form/index",
            "meta": {
              "title": "表單",
              "icon": "form"
            }
          }
        ]
      },
      {
        "path": "*",
        "redirect": "/404",
        "hidden": true
      }
    ]
  }

實際前端需要的 component是 component: () => import('@/views/content/classify'),

2.將后端傳回的"component": "Layout", 轉(zhuǎn)為 "component": Layout組件對象

因為有多級路由的出現(xiàn)白华,所以要寫成遍歷遞歸方法,確保把每個component轉(zhuǎn)成組件對象
因為后臺傳回的是字符串贩耐,所以要把加載組件的過程 封裝成一個方法弧腥,用這個方法在遍歷中使用;詳情查看項目里的router文件夾下的 _import_development.js和_import_production.js文件
Layout我放的目錄跟其他文件的目錄不一樣,所以我在遍歷里單獨處理潮太,各位小伙伴可自己調(diào)整哈

router 文件夾下的 _import_development.js
module.exports = file => require('@/views' + file + '.vue').default // vue-loader at least v13.0.0+
filterAsyncRouter方法 將后端返回的路由改為加載組件的過程
const _import = require('./router/_import_' + process.env.NODE_ENV) // 獲取組件的方法

import LayoutPage from '@/views/layout'  // Layout 是架構(gòu)組件管搪,不在后臺返回虾攻,在文件里單獨引入

function filterAsyncRouter(asyncRouterMap) { // 遍歷后臺傳來的路由字符串,轉(zhuǎn)換為組件對象
  const accessedRouters = asyncRouterMap.filter(route => {
    if (route.component) {
      if (route.component === 'Layout') { // Layout組件特殊處理
        route.component = LayoutPage 
      } else {
        route.component = _import(route.component)
      }
    }
    if (route.children && route.children.length) {
      route.children = filterAsyncRouter(route.children)
    }
    return true
  })

  return accessedRouters
}

3.使用beforeEach更鲁、addRoutes霎箍、localStorage來配合實現(xiàn)拿到數(shù)據(jù)再轉(zhuǎn)換成路由

beforeEach路由攔截,進(jìn)入判斷澡为,如果發(fā)現(xiàn)本地沒有路由數(shù)據(jù)漂坏,那就利用axios后臺取一次,取完以后媒至,利用localStorage存儲起來顶别,利用addRoutes動態(tài)添加路由,

ps:beforeEach好壞啊拒啰,一步小心就進(jìn)入到了他的死循環(huán)驯绎,瀏覽器都tm崩了,得在一開始就加判斷谋旦,拿到路由了剩失,就直接next(),嚶嚶嚶
global.antRouter是為了傳遞數(shù)據(jù)給左側(cè)菜單組件進(jìn)行渲染

import axios from 'axios'

var getRouter   //  用來獲取后臺拿到的路由

router.beforeEach((to, from, next) => {
  if (!getRouter) {  // 不加這個判斷册着,路由會陷入死循環(huán) (如果沒有路由)
    if (!getObjArr('router')) {  // 緩存里沒有路由拴孤,axios重新獲取
      axios.get('https://www.easy-mock.com/mock/5a5da330d9b48c260cb42ca8/example/antrouter').then(res => {
        getRouter = res.data.data.router//后臺拿到路由
        saveObjArr('router', getRouter) //存儲路由到localStorage

        routerGo(to, next) //  添加路由  執(zhí)行路由跳轉(zhuǎn)方法
      })
    } else { //  從localStorage拿到了路由
      getRouter = getObjArr('router')//拿到路由
      routerGo(to, next)  //  //  添加路由  執(zhí)行路由跳轉(zhuǎn)方法
    }
  } else {
    next()
  }

})

// routerGo
function routerGo(to, next) {
 // 這里后端返回的數(shù)據(jù)getRouter  可能不是我們需要的結(jié)構(gòu),那么需要先有一步轉(zhuǎn)換的步驟
// 直到轉(zhuǎn)換成前面第一步那種vue標(biāo)準(zhǔn)路由表的格式
  getRouter = filterAsyncRouter(getRouter)  // 過濾路由  轉(zhuǎn)換路由的component   
  // filterAsyncRoute方法是把后端返回的路由數(shù)據(jù) 轉(zhuǎn)換為前端要的路由結(jié)構(gòu)
  getRouter.push({ path: '*', redirect: '/404', hidden: true });
  router.addRoutes(getRouter) //動態(tài)添加路由
  global.antRouter = getRouter //將路由數(shù)據(jù)傳遞給全局變量甲捏,做側(cè)邊欄菜單渲染工作
  next({ ...to, replace: true })
}

function saveObjArr(name, data) { //localStorage 存儲數(shù)組對象的方法
  localStorage.setItem(name, JSON.stringify(data))
}

function getObjArr(name) { //localStorage 獲取數(shù)組對象的方法
  return JSON.parse(window.localStorage.getItem(name));

}

4.拿到遍歷好的路由演熟,進(jìn)行左側(cè)菜單渲染

上邊第三步會給 global.antRouter賦值,這是一個全局變量(可以用vuex替代)摊鸡,菜單那邊拿到路由绽媒,進(jìn)行渲染

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市免猾,隨后出現(xiàn)的幾起案子是辕,更是在濱河造成了極大的恐慌,老刑警劉巖猎提,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件获三,死亡現(xiàn)場離奇詭異,居然都是意外死亡锨苏,警方通過查閱死者的電腦和手機(jī)疙教,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伞租,“玉大人贞谓,你說我怎么就攤上這事】” “怎么了裸弦?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵祟同,是天一觀的道長。 經(jīng)常有香客問我理疙,道長晕城,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任窖贤,我火速辦了婚禮砖顷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赃梧。我一直安慰自己滤蝠,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布槽奕。 她就那樣靜靜地躺著几睛,像睡著了一般房轿。 火紅的嫁衣襯著肌膚如雪粤攒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天囱持,我揣著相機(jī)與錄音夯接,去河邊找鬼。 笑死纷妆,一個胖子當(dāng)著我的面吹牛盔几,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掩幢,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼逊拍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了际邻?” 一聲冷哼從身側(cè)響起芯丧,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎世曾,沒想到半個月后缨恒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡轮听,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年骗露,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片血巍。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡萧锉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出述寡,到底是詐尸還是另有隱情柿隙,我是刑警寧澤玫恳,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站优俘,受9級特大地震影響京办,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帆焕,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一惭婿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧叶雹,春花似錦财饥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至满着,卻和暖如春谦炒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背风喇。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工宁改, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人魂莫。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓还蹲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親耙考。 傳聞我的和親對象是個殘疾皇子谜喊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容