Vue中使用Element 以el-menu导航菜单形式展示Tree树形结构

2022-06-23 13:07:19

目的
项目分为全局路由如登录页面,404页面之类的和由侧边栏menu控制跳转的子路由页面主要是业务页面。页面子页面放入views文件夹下,将自动读入注册成route,配置文件主要用于生成树形menu侧边栏。建议配合项目结构进行阅读效果更佳

效果
在这里插入图片描述
项目结构
在这里插入图片描述
子页面配置文件
将根据以下配置文件生成树形menu导航栏

exportdefault[{
        url:"/page1",
        meta:{ title:'页面1', requiresAuth:false},
        children:[{
                url:"/page2",
                meta:{
                    requiresAuth:false,
                    title:"页面2"},
                children:[{
                        url:"/page3",
                        meta:{
                            requiresAuth:false,
                            title:"页面3"}},],},],},{
        url:"/page4",
        meta:{ title:'页面4', requiresAuth:false}}]

全局页面配置文件

exportdefault[{
        url:"/login",
        meta:{ title:'登录', requiresAuth:false}},]

侧边栏模板组件

sideBar组件

<template><divclass="side-bar-wrapper" @mouseenter="onMouseEnter" @mouseleave="onMouseLeave"><el-asideclass="index-aside":width="isSideBarExpand?'65px':'150px'"><divclass="title_banner"></div><el-menuclass="aside-menu":collapse="isSideBarExpand"
        ref="sideBar":default-active="onRoutes"
        text-color="#a5a5a5"
        active-text-color="#00c1de"
        background-color="#414549"
        unique-opened
        menu-trigger="click":collapse-transition="collapseTransition"><template v-for="(item) in menuList"><el-menu-item
            v-if="!item.list":index="item.route":key="item.route"
            @click="barHref(item.route)"><icon-svg:icon-class="item.icon":class="{'avtive_bar_icon':item.route== onRoutes,'bar_icon':item.route!= onRoutes}"/><span slot="title"class="bar_title">{{item.title}}</span></el-menu-item><TreeMenu:key="item.route+'s'" v-if="item.list":item="item"></TreeMenu></template></el-menu></el-aside></div></template><script>import pagefrom"@/config/router/pages.js";import TreeMenufrom"./menu";exportdefault{
  name:"sideBar",created(){this.getCachePage();},
  components:{ TreeMenu},data(){return{
      isCollapse:false,
      isSideBarExpand:true,
      collapseTransition:false,
      menuList:[]};},
  methods:{asyncgetCachePage(){this.menuList=this.creatMenu(page);},/* 
    保存被打开的侧边栏的状态
    */onMouseEnter(){this.isSideBarExpand=false;let menuRoute="";this.menuList.forEach(x=>{if(x.list&& x.list.length>0){if(
            x.list.find(y=>{return y.route===this.onRoutes;})){
            menuRoute= x.route;}}});if(menuRoute)this.$refs.sideBar.open(menuRoute);},onMouseLeave(){this.isSideBarExpand=true;},showSideBar(){this.isCollapse=!this.isCollapse;},creatMenu(list){var menuList=[];
      list.forEach(s=>{let menu={
          title: s.meta.title,
          icon: s.url.replace("/",""),
          index: s.url.replace("/",""),
          route: s.url,
          list:
            s.children&& s.children.length>0?this.creatMenu(s.children): undefined};
        menuList.push(menu);});return menuList;},barHref(s){if(s==this.onRoutes)returnthis.$router.push({ path: s});}},
  computed:{onRoutes(){returnthis.$route.path;}}};</script><style lang="scss">.side-bar-wrapper{
  height:100%;
  z-index:20;}.title_banner{
  width:100%;
  height:50px;}.side-bar-wrapper.index-aside{
  overflow: hidden;
  position: absolute;
  left:0;
  top:0;
  bottom:0;
  z-index:20;// padding-top: 20px;
  background: #414549;-webkit-transition: width0.3s;
  transition: width0.3s;.el-menu{
    border-right: none;.el-menu-item{// padding-left: 20px !important;}}}.side-bar-wrapper.index-aside.aside-menu{
  height:100%;}.side-bar-wrapper.index-aside.aside-menu.nav-icon{
  width:20px;
  height:20px;}.side-bar-wrapper.index-aside.el-menu{
  overflow: hidden;}.bar_icon{
  color: #fff;}.avtive_bar_icon{
  color: #00c1de;}.bar_title{
  margin-left:5px;}</style>

menu组件
主要用于树形嵌套结构

<template><el-submenu
    v-if="item.title&&item.list":index="item.route":key="item.route":show-timeout="0":hide-timeout="0"><template slot="title"><div><icon-svg:icon-class="item.icon":class="{'avtive_bar_icon':inParentPage(item.list,onRoutes),'bar_icon':!inParentPage(item.list,onRoutes)}"/><span slot="title" style="margin-left:3px">{{item.title}}</span></div></template><template v-for="(it) in item.list"><el-menu-item v-if="!it.list":index="it.route":key="it.route" 	  @click="barHref(it.route)"><icon-svg:icon-class="it.icon":class="{'avtive_bar_icon':it.route== onRoutes,'bar_icon':it.route!= onRoutes}"/><span slot="title"class="bar_title">{{it.title}}</span></el-menu-item><TreeMenu:key="it.route+'s'" v-if="it.list":item="it"></TreeMenu></template></el-submenu></template><script>exportdefault{
  props:["item"],
  name:"TreeMenu",
  methods:{barHref(s){if(s==this.onRoutes)returnthis.$router.push({ path: s});},inParentPage(list,page){let flag=falsefunctionloop(pages,p){for(let i=0;i<pages.length;i++){if(pages[i].route==p){
            flag=true;break}if(pages[i].list){loop(pages[i].list,page)}}}loop(list,page)return flag},},
  computed:{onRoutes(){returnthis.$route.path;}}};</script><style scoped lang='scss'>.bar_icon{
  color: #fff;}.avtive_bar_icon{
  color: #00c1de;}.bar_title{
  margin-left:5px;}</style>

结合Element 布局组件,生成主页面

<template><el-containerclass="content"><side-bar></side-bar><el-containerclass="main-container"><el-header style="height:50px"><common-header ref="commomHeader"></common-header></el-header><el-main><router-view:key="key"></router-view></el-main></el-container></el-container></template><script>import sideBarfrom"./sideBar.vue";import commonHeaderfrom"./commonHeader.vue";exportdefault{
  components:{ sideBar, commonHeader},
  computed:{key(){returnthis.$route.name!== undefined?this.$route.name++newDate():this.$route++newDate();}}};</script><style lang='scss'>.el-container{
  position: relative;}.el-header{
  padding:0px;}.main-container{
  margin-left:65px;}</style>

vue router 配置,读取页面配置文件自动注册路由

import pagefrom'./pages.js'import globalPagefrom'./globalPages.js'import Routerfrom'vue-router'const vueRouter=newRouter({
    mode:'history',
    routes:[...getRouteList(globalPage)]})
vueRouter.addRoutes([{
        path:'/',
        name:'index',
        component: resolve=>require(["@/globalViews/main/main.vue"], resolve),
        children:[...getRouteList([...page])],// redirect: page[0].url // 默认index重定向到home页面}])// 全局钩子,单独页面钩子在配置项单独设置
vueRouter.beforeEach((to,from, next)=>{if(to.meta.requiresAuth&&!localStorage.getItem("Token")){
        console.warn('没有权限,跳转到登录')next('/login')}else{next()}})// 根据配置生成route对象集合functiongetRouteList(routes){let res=[]lethander=function(list){
        list.forEach((s)=>{if(s.children){hander(s.children)}if(s.url){let route={
                    path: s.url,
                    component: resolve=>require(["@/views"+ s.url+ s.url+".vue"], resolve),
                    name: s.url.replace('/',''),
                    meta: s.meta}
                res.push(route)}})}hander(routes)// console.log(res)return res}exportdefault vueRouter;

将Router配置注入Vue构造

import Vuefrom'vue'import Appfrom'./App.vue'import VueRouterfrom'vue-router';import routerfrom'@/config/router/index'

Vue.config.productionTip=false
Vue.use(VueRouter)newVue({
  router,
  render: h=>h(App),}).$mount('#app')

总结
还是react清晰好使
https://blog.csdn.net/weixin_39168678/article/details/107315893

  • 作者:白马湖小龙王
  • 原文链接:https://blog.csdn.net/weixin_39168678/article/details/107400525
    更新时间:2022-06-23 13:07:19