寫背景管理系統,估計有不少人遇過這樣的需求:根據背景資料動态添加路由和菜單。
為什麼這麼做呢?因為不同的使用者有不同的權限,能通路的頁面是不一樣的。
在網上找了好多資料,終于想到了解決辦法。
動态生成路由
利用 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
不停的對子數組進行循環,生成三級菜單。
動态菜單這樣就可以實作了。
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)
})
}
}