更多文章
寫后台管理系統,估計有不少人遇過這樣的需求:根據后台數據動態添加路由和菜單。
為什么這么做呢?因為不同的用戶有不同的權限,能訪問的頁面是不一樣的。
在網上找了好多資料,終於想到了解決辦法。
動態生成路由
利用 vue-router 的 addRoutes
方法可以動態添加路由。
先看一下官方介紹:
router.addRoutes
router.addRoutes(routes: Array<RouteConfig>)
動態添加更多的路由規則。參數必須是一個符合 routes
選項要求的數組。
舉個例子:
const router = new Router({
routes: [
{
path: '/login',
name: 'login',
component: () => import('../components/Login.vue')
},
{path: '/', redirect: '/home'},
]
})
上面的代碼和下面的代碼效果是一樣的
const router = new Router({
routes: [
{path: '/', redirect: '/home'},
]
})
router.addRoutes([
{
path: '/login',
name: 'login',
component: () => import('../components/Login.vue')
}
])
在動態添加路由的過程中,如果有 404 頁面,一定要放在最后添加,否則在登陸的時候添加完頁面會重定向到 404 頁面。
類似於這樣,這種規則一定要最后添加。
{path: '*', redirect: '/404'}
動態生成菜單
假設后台返回來的數據長這樣
// 左側菜單欄數據
menuItems: [
{
name: 'home', // 要跳轉的路由名稱 不是路徑
size: 18, // icon大小
type: 'md-home', // icon類型
text: '主頁' // 文本內容
},
{
text: '二級菜單',
type: 'ios-paper',
children: [
{
type: 'ios-grid',
name: 't1',
text: '表格'
},
{
text: '三級菜單',
type: 'ios-paper',
children: [
{
type: 'ios-notifications-outline',
name: 'msg',
text: '查看消息'
},
{
type: 'md-lock',
name: 'password',
text: '修改密碼'
},
{
type: 'md-person',
name: 'userinfo',
text: '基本資料',
}
]
}
]
}
]
來看看怎么將它轉化為菜單欄,我在這里使用了 iview
的組件,不用重復造輪子。
<!-- 菜單欄 -->
<Menu ref="asideMenu" theme="dark" width="100%" @on-select="gotoPage"
accordion :open-names="openMenus" :active-name="currentPage" @on-open-change="menuChange">
<!-- 動態菜單 -->
<div v-for="(item, index) in menuItems" :key="index">
<Submenu v-if="item.children" :name="index">
<template slot="title">
<Icon :size="item.size" :type="item.type"/>
<span v-show="isShowAsideTitle">{{item.text}}</span>
</template>
<div v-for="(subItem, i) in item.children" :key="index + i">
<Submenu v-if="subItem.children" :name="index + '-' + i">
<template slot="title">
<Icon :size="subItem.size" :type="subItem.type"/>
<span v-show="isShowAsideTitle">{{subItem.text}}</span>
</template>
<MenuItem class="menu-level-3" v-for="(threeItem, k) in subItem.children" :name="threeItem.name" :key="index + i + k">
<Icon :size="threeItem.size" :type="threeItem.type"/>
<span v-show="isShowAsideTitle">{{threeItem.text}}</span>
</MenuItem>
</Submenu>
<MenuItem v-else v-show="isShowAsideTitle" :name="subItem.name">
<Icon :size="subItem.size" :type="subItem.type"/>
<span v-show="isShowAsideTitle">{{subItem.text}}</span>
</MenuItem>
</div>
</Submenu>
<MenuItem v-else :name="item.name">
<Icon :size="item.size" :type="item.type" />
<span v-show="isShowAsideTitle">{{item.text}}</span>
</MenuItem>
</div>
</Menu>
代碼不用看得太仔細,理解原理即可,其實就是通過三次 v-for
不停的對子數組進行循環,生成三級菜單。
動態菜單這樣就可以實現了。
動態路由,因為上面已經說過了用 addRoutes
來實現,現在看看具體怎么做。
首先,要把項目所有的頁面路由都列出來,再用后台返回來的數據動態匹配,能匹配上的就把路由加上,不能匹配上的就不加。
最后把這個新生成的路由數據用 addRoutes
添加到路由表里。
const asyncRoutes = {
'home': {
path: 'home',
name: 'home',
component: () => import('../views/Home.vue')
},
't1': {
path: 't1',
name: 't1',
component: () => import('../views/T1.vue')
},
'password': {
path: 'password',
name: 'password',
component: () => import('../views/Password.vue')
},
'msg': {
path: 'msg',
name: 'msg',
component: () => import('../views/Msg.vue')
},
'userinfo': {
path: 'userinfo',
name: 'userinfo',
component: () => import('../views/UserInfo.vue')
}
}
// 傳入后台數據 生成路由表
menusToRoutes(menusData)
// 將菜單信息轉成對應的路由信息 動態添加
function menusToRoutes(data) {
const result = []
const children = []
result.push({
path: '/',
component: () => import('../components/Index.vue'),
children,
})
data.forEach(item => {
generateRoutes(children, item)
})
children.push({
path: 'error',
name: 'error',
component: () => import('../components/Error.vue')
})
// 最后添加404頁面 否則會在登陸成功后跳到404頁面
result.push(
{path: '*', redirect: '/error'},
)
return result
}
function generateRoutes(children, item) {
if (item.name) {
children.push(asyncRoutes[item.name])
} else if (item.children) {
item.children.forEach(e => {
generateRoutes(children, e)
})
}
}
所有的代碼實現,我都放在 github 上,動態菜單的實現放在這個項目下的 src/components/Index.vue
、src/permission.js
和 src/utils/index.js
下