- 
左中右菜单布局

<template> <el-container> <el-menu class="el-menu-vertical-demo" style="width: 80px; height: 100vh;" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" @select="handleSelect" @open="handleOpen" @close="handleClose" :collapse="isCollapse"> <el-menu-item :index="item.path" :key="item.path" v-for="item in sidebarRouters" v-if="item.meta" > <i class="el-icon-menu"> <div style="font-size: 14px"><y>{{ item.meta.title.substring(0, 2) }}</y></div> </i> </el-menu-item> </el-menu> <el-menu style="width: 200px; height: 100vh;" class="el-menu-vertical-demo" background-color="#545c64" text-color="#fff" router active-text-color="#ffd04b"> <el-menu-item :index="item.path" :key="item.path" v-for="(item , index) in menuChildArr"> <i class="el-icon-menu"></i> <span >{{item.name}}</span> </el-menu-item> </el-menu> <div class="scroll-box"> <el-main> <router-view></router-view> </el-main> </div> </el-container> </template> <style> .el-menu-vertical-demo:not(.el-menu--collapse) { width: 200px; min-height: 400px; } .scroll-box { width: 100%; height: 100vh; /* 占据屏幕高度的 50% */ overflow-y: auto; /* 垂直滚动 */ box-sizing: border-box; } </style> <script> import store from "@/store"; export default { data() { return { sidebarRouters: store.getters.sidebarRouters, countIndex: 0, menuChildMap:{}, menuChildArr: [ { name: '用户管理', path: '/system/user' }, { name: '角色管理', path: '/system/role' }], isCollapse: true }; }, methods: { handleOpen(key, keyPath) { }, handleSelect(key, keyPath){ console.log("AAAAAAA="+ keyPath); console.log(key, keyPath); this.countIndex++; this.menuChildArr=[]; let sidebarRouters = this.sidebarRouters; for (let i = 0; i < sidebarRouters.length; i++) { let item = sidebarRouters[i]; if (item.meta && item.path==keyPath) { let title = item.meta.title; let children = item.children; for (let j = 0; j < children.length; j++) { let child = children[j]; console.log("PPPPP:"+item.path+'/'+child.path); this.menuChildArr.push({name:child.meta.title, path:item.path+'/'+child.path}); } } } console.log(JSON.stringify(this.menuChildArr)); }, handleClose(key, keyPath) { console.log(key, keyPath); } } } </script> - 
左右菜单布局

<template> <el-container> <el-header style="background-color:#545c64;color: #fff;height: 7vh;"> <h1>TMS运输管理系统</h1> </el-header> <el-container> <div class="menu-container"> <el-menu :default-active="activeIndex2" class="custom-menu" mode="vertical" @select="handleSelect" background-color="#545c64" text-color="#fff" router active-text-color="#ffd04b"> <el-submenu style="background-color: #545c64;" :index="item.path" :key="item.path" v-for="item in sidebarRouters" v-if="item.meta"> <template slot="title" style="background-color: #545c64;">{{ item.meta.title }}</template> <el-menu-item style="background-color: #545c64;" :key="child.path" :index="item.path+'/'+child.path" v-for="child in item.children" v-if="child.meta" > {{ child.meta.title }} </el-menu-item> </el-submenu> <!-- <el-menu-item index="/bar" >消息中心</el-menu-item> <el-menu-item index="/foo" >消息中心2</el-menu-item> <el-menu-item index=""><a href="https://www.ele.me" target="_blank">订单管理</a></el-menu-item>--> </el-menu> </div> <div class="scroll-box"> <!-- 路由出口 --> <!-- 路由匹配到的组件将渲染在这里 --> <el-tag style="margin: 5px;" :key="tag" v-for="(tag ,index) in dynamicTags" closable :disable-transitions="false" :effect="tag.effect" @click="handleClick(tag)" @close="handleClose(tag)"> <router-link :to="tag.path"> {{tag.name}} </router-link> </el-tag> <router-view></router-view> </div> </el-container> </el-container> </template> <script> import {mapState} from "vuex"; import store from '@/store' export default { name: 'Layout', data() { return { effectValue:'plain', dynamicTags: [{name:'首页',path:'/',effect:'plain'}], activeIndex2: '0', menuIndexName:{'/system/user':'用户管理', '/system/role':'角色管理', '/system/menu':'菜单管理', '/system/dept':'部门管理', '/system/dict':'字典管理', '/system/post':'岗位管理','/system/job':'任务管理', '/system/config':'参数管理', '/system/notice':'通知公告', '/system/logininfor':'登录日志', '/system/operlog':'操作日志'}, sidebarRouters: store.getters.sidebarRouters }; }, methods: { handleSelect(key, keyPath) { //console.log(JSON.stringify(store.getters.sidebarRouters)) console.log(key, keyPath); let menuIndexName1 = new Map(); let sidebarRouters = this.sidebarRouters; console.log("PPPPPFull111:"+JSON.stringify(sidebarRouters)); for (let i = 0; i < sidebarRouters.length; i++) { let item = sidebarRouters[i]; if (item.meta) { let title = item.meta.title; let children = item.children; for (let j = 0; j < children.length; j++) { let child = children[j]; let pathFull = item.path+'/'+child.path; let titleChild = child.meta.title; console.log("PPPPP:"+pathFull,titleChild); menuIndexName1.set(pathFull,titleChild); // ={item.path+'/'+child.path:child.meta.title}; } } } console.log("PPPPPFull:"+JSON.stringify(menuIndexName1)); //置灰其它菜单按钮tag this.dynamicTags.forEach(item => { item.effect='plain'; }); //激活当前菜单按钮tag let menuName = menuIndexName1.get(keyPath[1]); let menuNameJson={name:menuName, path:keyPath[1],effect:'dark'}; this.dynamicTags.push(menuNameJson); //this.$router.push({path: keyPath}); }, handleClose(tag) { this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1); //激活后一个按钮tag if(this.dynamicTags.length>1){ let dynamicTagsCur = this.dynamicTags[this.dynamicTags.length-1]; dynamicTagsCur.effect='dark'; let returnUrl = dynamicTagsCur.path; //刷新路由 //this.$router.replace(decodeURIComponent(returnUrl || '/')); this.$router.push({ path: returnUrl, query: { ...this.$route.query, timestamp: Date.now() } }); } }, handleClick(tag){ //置灰其它菜单按钮tag this.dynamicTags.forEach(item => { item.effect='plain'; }); //单击事件激活当前按钮 tag.effect='dark'; } } }; </script> <style scoped lang="scss"> .el-tag + .el-tag { margin: 5px; } .menu-container { display: flex; width: 15vw; height: 93vh; /* 占据整个视口高度 */ } .custom-menu { flex: 1; height: 100%; /* 高度自适应父容器 */ } .scroll-box { width: 100%; height: 93vh; /* 占据屏幕高度的 50% */ overflow-y: auto; /* 垂直滚动 */ box-sizing: border-box; } </style> - 
上下菜单布局
 

<template>
  <div id="app">
    <el-menu
      :default-active="activeIndex2"
      class="el-menu-demo"
      mode="horizontal"
      @select="handleSelect"
      background-color="#545c64"
      text-color="#fff"
      router
      active-text-color="#ffd04b">
      <el-submenu :index="item.path" :key="item.path" v-for="item in sidebarRouters" v-if="item.meta">
        <template slot="title" >{{ item.meta.title }}</template>
        <el-menu-item  :key="child.path" :index="item.path+'/'+child.path" v-for="child in item.children" v-if="child.meta" >
          {{ child.meta.title }}
        </el-menu-item>
      </el-submenu>
      <!--
      <el-menu-item index="/bar" >消息中心</el-menu-item>
      <el-menu-item index="/foo" >消息中心2</el-menu-item>
      <el-menu-item index=""><a href="https://www.ele.me" target="_blank">订单管理</a></el-menu-item>-->
    </el-menu>
    <!-- 路由出口 -->
    <!-- 路由匹配到的组件将渲染在这里 -->
    <el-tag
      :key="tag"
      v-for="(tag ,index) in dynamicTags"
      closable
      :disable-transitions="false"
      :effect="tag.effect"
      @click="handleClick(tag)"
      @close="handleClose(tag)">
      <router-link :to="tag.path"> {{tag.name}} </router-link>
    </el-tag>
    <router-view></router-view>
  </div>
</template>
<script>
import {mapState} from "vuex";
import store from '@/store'
export default {
  name: 'Layout',
  data() {
    return {
      effectValue:'plain',
      dynamicTags: [{name:'首页',path:'/',effect:'plain'}],
      activeIndex2: '0',
      menuIndexName:{'/system/user':'用户管理', '/system/role':'角色管理',  '/system/menu':'菜单管理',  '/system/dept':'部门管理', '/system/dict':'字典管理', '/system/post':'岗位管理','/system/job':'任务管理', '/system/config':'参数管理', '/system/notice':'通知公告', '/system/logininfor':'登录日志', '/system/operlog':'操作日志'},
      sidebarRouters: store.getters.sidebarRouters
    };
  },
  methods: {
    handleSelect(key, keyPath) {
      //console.log(JSON.stringify(store.getters.sidebarRouters))
      console.log(key, keyPath);
      let menuIndexName1 = new Map();
      let sidebarRouters = this.sidebarRouters;
      console.log("PPPPPFull111:"+JSON.stringify(sidebarRouters));
      for (let i = 0; i < sidebarRouters.length; i++) {
        let item = sidebarRouters[i];
        if (item.meta) {
          let title = item.meta.title;
          let children = item.children;
          for (let j = 0; j < children.length; j++) {
            let child = children[j];
            let pathFull = item.path+'/'+child.path;
            let titleChild = child.meta.title;
            console.log("PPPPP:"+pathFull,titleChild);
            menuIndexName1.set(pathFull,titleChild); // ={item.path+'/'+child.path:child.meta.title};
          }
        }
      }
      console.log("PPPPPFull:"+JSON.stringify(menuIndexName1));
      //置灰其它菜单按钮tag
      this.dynamicTags.forEach(item => {
        item.effect='plain';
      });
      //激活当前菜单按钮tag
      let menuName = menuIndexName1.get(keyPath[1]);
      let menuNameJson={name:menuName, path:keyPath[1],effect:'dark'};
      this.dynamicTags.push(menuNameJson);
      //this.$router.push({path: keyPath});
    },
    handleClose(tag) {
      this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);
      //激活后一个按钮tag
      if(this.dynamicTags.length>1){
        let dynamicTagsCur = this.dynamicTags[this.dynamicTags.length-1];
        dynamicTagsCur.effect='dark';
        let returnUrl = dynamicTagsCur.path;
        //刷新路由
        //this.$router.replace(decodeURIComponent(returnUrl || '/'));
        this.$router.push({
          path: returnUrl,
          query: {
            ...this.$route.query,
            timestamp: Date.now()
          }
        });
      }
    },
    handleClick(tag){
      //置灰其它菜单按钮tag
      this.dynamicTags.forEach(item => {
        item.effect='plain';
      });
      //单击事件激活当前按钮
      tag.effect='dark';
    }
  }
};
</script>
<style scoped lang="scss">
.el-tag {
  margin: 5px;
}
</style>