1.数据准备
树形菜单基本数据很简单,只需要菜单id,菜单名称,路由地址,图标。下图中的节点id和父节点id是为了后端生成树形数据,只负责前端的话只需要拿到前面说的四个数据就行。
后端将数据转成树形结构,传给前端的数据结构如图
2.选择组件
我直接用element-ui的el-menu组件,结构是(这是用来注释的,完整代码在后面)
<el-menu>
<template v-for="(item, key) in menuList">-----前端得到的数据存放到menuList数组
<el-submenu :key="key" v-if="item.children && item.children.length!==0" :index="item.m_url">----父级菜单,判断有子节点,index是路由跳转
<template slot="title">----插槽
<i :class="item.m_icon"></i>-----图标
<span>{{ item.m_name }}</span>----菜单名称
</template>
<el-menu-item v-for="(val, index) in item.children" :index="val.m_url" :key="index">----二级菜单
<template slot="title">
<i :class="val.m_icon"></i>
<span>{{ val.m_name }}</span>
</template>
</el-menu-item>
</el-submenu>
<el-submenu v-else :key="item.m_n_id" :index="item.m_url">没有子节点
<template slot="title">
<i :class="item.m_icon"></i>
<span>{{ item.m_name }}</span>
</template>
</el-submenu>
</template>
</el-menu>
3.配置路由
跳转到那个页面是由写在router目录下的index.js的component指定的
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
// mode: 'history',
routes: [
{
path: '/',
name: 'home',
meta: {
key: '1'
},
component: () => import("@/views/home"),
children: [{
path: '/courseApplication', // 这个路径必须与后端传回数据的m_url字段相对应
name: 'courseApplication',
meta: {
key: '1-1'
},
component: () => import('@/views/trainManage/courseApplication') // 要跳转的页面路径
}]
}
]
})
4.不出问题这样就可以实现动态路由了
5.完整代码
menu.vue
<template>
<div class="menu">
<el-menu
class="el-menu-vertical-demo"
@open="handleOpen"
@close="handleClose"
background-color="rgb(255,255,255)"
text-color="rgb(28,41,89)"
router = router
active-text-color="rgb(28,41,89)">
<template v-for="(item, key) in menuList">
<el-submenu :key="key" v-if="item.children && item.children.length!==0" :index="item.m_url">
<template slot="title">
<i :class="item.m_icon"></i>
<span>{{ item.m_name }}</span>
</template>
<el-menu-item v-for="(val, index) in item.children" :index="val.m_url" :key="index">
<template slot="title">
<i :class="val.m_icon"></i>
<span>{{ val.m_name }}</span>
</template>
</el-menu-item>
</el-submenu>
<el-submenu v-else :key="item.m_n_id" :index="item.m_url">
<template slot="title">
<i :class="item.m_icon"></i>
<span>{{ item.m_name }}</span>
</template>
</el-submenu>
</template>
</el-menu>
</div>
</template>
<script>
import { mapActions } from 'vuex';
export default {
name: "asideItem",
data(){
return{
router: true,
isCollapse: true,
label: false,
menuList: []
}
},
mounted() {
this.getMenu()
},
methods: {
...mapActions([
'getMenuList'
]),
handleOpen(key, keyPath) {
console.log(key, keyPath);
},
handleClose(key, keyPath) {
console.log(key, keyPath);
},
labelChange: function() {
console.log(this.label);
},
getMenu: function() { // 从后台获取菜单列表
this.getMenuList().then(res => {
if(res.errno === 0) {
this.menuList = res.data
} else {
this.$message.error(res.data)
}
}).catch(error => { this.$message.error(error) })
}
}
};
</script>
<style lang="postcss" scoped>
.menu {
transition: width 0.28s ease-out;
width: 180px;
background: rgb(255, 255, 255);
height: calc(100vh - 46px);
& .el-menu{
width: 100%;
border-right: none;
}
& :hover {
}
}
</style>
<style>
.el-menu-item:hover{
outline: 0 !important;
background-color: rgb(232,240,255)!important;
}
.el-menu-item.is-active {
background: rgb(210,226,255) !important;
}
.el-submenu__title:focus, .el-submenu__title:hover{
outline: 0 !important;
background: none !important;
}
</style>
router 下的index.js根据具体数据进行配置
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
// mode: 'history',
routes: [
{
path: '/',
name: 'home',
meta: {
key: '1'
},
component: () => import("@/views/home"),
children: [{
path: '/courseApplication', // 这个路径必须与后端传回数据的m_url字段相对应
name: 'courseApplication',
meta: {
key: '1-1'
},
component: () => import('@/views/trainManage/courseApplication') // 要跳转的页面路径
}]
}
]
})
-----------------------这是分割线(以下是修改前的)-----------------------
将目录作为子目录添加到首页下面,可以显示出来,但是第二次点击同一个菜单时,会出现
地址叠加的情况,导致页面不能显示。而且先点击到别的页面也会出现这种情况
解决办法:在获取动态列表的时候,数据里面有url和source,不要去获取source,内层外层循环都获取url,然后在router/index 里面,path改为跟获取的url一样的内容
这个path主要是为了匹配菜单,最终调取页面是由component完成的。
刚开始的时候还有一个问题:
就是点击菜单栏的某一项,会全屏显示某一个页面,而不是懒加载的方式,只显示在中间部分,解决办法是将获取的路由放在跟路由下面,作为子组件呈现出来
完整代码
<el-menu
:default-active="this.$route.path"
class="el-menu-vertical"
router
:collapse="iscollapse"
:collapse-transition="false"
:active-text-color="variables.menuActiveText"
:background-color="variables.menuBg"
:text-color="variables.menuText"
>
<fragment>
<template v-for="item in menuList">
<fragment v-if="item != null" :key="item.url">
<el-submenu v-if="item.childMenuInfoTreeSet && item.childMenuInfoTreeSet.length > 0" :key="item.url" :index="item.url.toString()">
<template slot="title">
<i :class="item.iconcls.toString()" class="iconSize" />
<span slot="title">{{ item.menuName }}</span>
</template>
<el-menu-item v-for="val in item.childMenuInfoTreeSet" :key="val.title" :index="val.url.toString()">
<i :class="val.iconcls.toString()" class="iconSize" />
<span slot="title">{{ val.menuName }}</span>
</el-menu-item>
</el-submenu>
<el-menu-item v-else :key="item.url" :index="item.url.toString()">
<i :class="item.iconcls" class="iconSize" />
<span slot="title">{{ item.menuName }}</span>
</el-menu-item>
</fragment>
</template>
</fragment>
</el-menu>
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。