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>
以上为个人经验,希望能给大家一个参考,也希望大家多多支持阿兔在线工具。