Vue 動態路由的實現(後臺傳遞路由,前端拿到並生成側邊欄)

2019.4.28號更新:
鑑於你們有不少疑問,特意建立了羣1020135830,有問題的多交流交流;前端

2019.4.3號更新:
我說爲啥點進來看不到最新的評論,今天才發現是被摺疊了,
這篇教程你們理解起來若是有難度的話,
參考下把路由表寫到本地,後端返回用戶角色去作匹配這種方式,適合上手:本地寫好路由,向後端請求用戶的角色
如下爲原答案:vue

地獄空蕩蕩,師兄在土創。雖然土,可是能夠療傷。

前言

vue項目實現 動態路由的方式大致可分爲兩種:
1.前端這邊把路由寫好,登陸的時候根據用戶的角色權限來動態展現路由,(前端控制路由)
詳情可參閱 花褲衩大佬的項目 手把手...,我當時看這個項目看了很久才明白一點邏輯,
由於大神的動態路由那裏有好多層判斷,而且穿插各類vuex,把小白的我都快搞懵逼了,對我啓發很大,也正是這篇文章,給我提供了不少邏輯
2.後臺傳來當前用戶對應權限的路由表,前端經過調接口拿到後處理(後端處理路由)
這兩種方法各有優勢,效果都能實現,咱們公司是經過第二中種方法實現的,緣由就是公司項目裏有一個專門的用戶中心,裏邊邏輯很複雜,很差返給前端用戶權限,擔憂路由放到前端
不安全(以上的話是公司的後臺同窗講的),那好吧,抱着都試試、鍛鍊下本身能力的態度,
咱們搞了第二種方法。

今天咱們來說講用後臺傳遞路由表實現動態路由的思路,由於公司的項目里路有部分用到了vuex,我就把路由部分脫離vuex整理了出來,讓你們有個啓發,並非絕對的解決方案,只是思路
github:https://github.com/Mrblackant...
在線查看:http://an888.net/antRouter/#/...
圖片描述ios

思路整理

如下四步驟對應的代碼都在下方會講到,而且是對應的git

1.後臺同窗返回一個json格式的路由表,我用easymock造了一段: 動態路由表,你們可參考;
2.由於後端同窗傳回來的都是 字符串格式的,可是前端這裏須要的是一個組件對象啊,寫個方法遍歷一下,將字符串轉換爲組件對象;
3.利用vue-router的beforeEach、addRoutes、localStorage來配合上邊兩步實現效果;
4.左側菜單欄根據拿到轉換好的路由列表進行展現;
大致步驟:攔截路由->後臺取到路由->保存路由到localStorage(用戶登陸進來只會從後臺取一次,其他都從本地取,因此用戶,只有退出在登陸路由纔會更新)

代碼

1.路由表github

每一個路由都使用到組件 Layout,這個組件是總體的頁面佈局:左側菜單列,右側頁面,因此children下邊的第一級路由就是你本身的開發的頁面,meta裏包含着路由的名字,以及路由對應的icon;
由於可能會有多級菜單,因此會出現children下邊嵌套children的狀況;
路由是數組格式
"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
      }
    ]
  }

2.將後端傳回的"component": "Layout", 轉爲"component": Layout組件對象vue-router

由於有多級路由的出現,因此要寫成遍歷遞歸方法,確保把每一個component轉成對象,
由於後臺傳回的是字符串,因此要把加載組件的過程 封裝成一個方法(此處參考 花褲衩大神的解決方法),用這個方法在遍歷中使用;詳情查看項目裏的router文件夾下的 _import_development.js和_import_production.js文件
Layout我放的目錄跟其餘文件的目錄不同,因此我在遍歷裏單獨處理,各位小夥伴可本身調整哈
const _import = require('./router/_import_' + process.env.NODE_ENV)//獲取組件的方法
import Layout from '@/views/layout' //Layout 是架構組件,不在後臺返回,在文件裏單獨引入

function filterAsyncRouter(asyncRouterMap) { //遍歷後臺傳來的路由字符串,轉換爲組件對象
  const accessedRouters = asyncRouterMap.filter(route => {
    if (route.component) {
 **加粗文字**     if (route.component === 'Layout') {//Layout組件特殊處理
        route.component = Layout
      } 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來配合實現vuex

beforeEach路由攔截,進入判斷,若是發現本地沒有路由數據,那就利用axios後臺取一次,取完之後,利用localStorage存儲起來,利用addRoutes動態添加路由,
ps:beforeEach好壞啊,一步當心就進入到了他的死循環,瀏覽器都tm崩了,得在一開始就加判斷,拿到路由了,就直接next(),嚶嚶嚶
global.antRouter是爲了傳遞數據給左側菜單組件進行渲染
import axios from 'axios'

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

router.beforeEach((to, from, next) => {
  if (!getRouter) {//不加這個判斷,路由會陷入死循環
    if (!getObjArr('router')) {
      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)//執行路由跳轉方法
      })
    } else {//從localStorage拿到了路由
      getRouter = getObjArr('router')//拿到路由
      routerGo(to, next)
    }
  } else {
    next()
  }

})


function routerGo(to, next) {
  getRouter = filterAsyncRouter(getRouter) //過濾路由
  router.addRoutes(getRouter) //動態添加路由
  global.antRouter = getRouter //將路由數據傳遞給全局變量,作側邊欄菜單渲染工做
  next({ ...to, replace: true })
}

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

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

}

4.拿到遍歷好的路由,進行左側菜單渲染json

上邊第三部會給 global.antRouter賦值,這是一個全局變量(能夠用vuex替代),菜單那邊拿到路由,進行渲染,這裏又是參考了 花褲衩大神的layout部分 ,這裏我就不貼代碼了

才疏學淺,但願你們多多指正,尤爲對於路由攔截那部分,應該還有不少優化的地方,歡迎指正axios

相關文章
相關標籤/搜索