视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Vue 动态添加路由及生成菜单的方法示例
2020-11-27 21:54:53 责编:小采
文档


写后台管理系统,估计有不少人遇过这样的需求:根据后台数据动态添加路由和菜单。

为什么这么做呢?因为不同的用户有不同的权限,能访问的页面是不一样的。

在网上找了好多资料,终于想到了解决办法。

动态生成路由

利用 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下

下载本文
显示全文
专题