vue 点击菜单动态生成Tab

  • 2020 年 2 月 20 日
  • 笔记

UI 组件采用element  NavMenu点击左侧的菜单列表生成Tab,如下图

查看效果链接

主要思路

(1)点击菜单列表的时生成tab数据

(2)点击tab 展示当前激活tab的信息

(3)点击关闭按钮移除tab的数据,如果删除的是当前激活的tab,激活的tab前移或后移(删除tab的前一个或者后一个)

(4)采用动态组件展示每个tab的具体内容

这个例子中菜单列表没有采用路由跳转,采用路由与不采用路由跳转动态生成Tab 的原理都是一样的。

Home.vue

<template>    <div>      <el-container :style="{height: containerHeight, border: '1px solid #eee'}" id="con">        <el-header style="background:#3c8dbc;"><i class="fa fa-bars collapseBtn" @click="handleCollapseClick"></i>        </el-header>        <el-container>          <el-aside :width="asideWidth">            <el-menu            :default-active="activeMenuItem"            :collapse="isCollapse"            :collapse-transition="false"             >              <el-submenu v-for="item in menuData" :index="item.id+''" :key="item.id">                <template slot="title">                  <i class="el-icon-location"></i>                  <span>{{item.name}}</span>                </template>                <el-menu-item                  v-for="innerItem in item.children"                  :index="innerItem.id.toString()"                  :key="innerItem.id"                  @click="handleItemClick(innerItem)"                >{{innerItem.name}}</el-menu-item>              </el-submenu>            </el-menu>          </el-aside>          <el-container>            <el-main>              <el-tabs :value="activeTabItem" @tab-remove="closeTab" @tab-click="tabClick">                <el-tab-pane                  v-for="item in tabs"                  :label="item.label"                  :key="item.id"                  :name="item.id"                  :closable="item.closable"                >                <!-- <tab-content :tabData = "item.label"></tab-content> -->                <async-component :componentPath="item.component"></async-component>                </el-tab-pane>              </el-tabs>              </el-main>            <el-footer>             footer            </el-footer>          </el-container>        </el-container>      </el-container>    </div>  </template>    <script>  import TabContent  from "@/components/TabContent.vue"  import AsyncComponent from "./AsyncComponent";  //import AdminIndex from "@/components/AdminIndex.vue";  export default {    data() {      return {        containerHeight: "",        asideWidth:"230px",        isCollapse:false,        menuData: [          {            name: "导航1",            id: 1,            children: [              {                name: "导航1-选项1",                id: 2,                componentPath:"Item1.vue"              },              {                name: "导航1-选项2",                id: 3,                componentPath:"Item2.vue"              }            ]          },          {            name: "导航2",            id: 4,            children: [              {                name: "导航2-选项1",                id: 5,                componentPath:"Item3.vue"              },              {                name: "导航2-选项2",                id: 6,                componentPath:"Item4.vue"              }            ]          }        ],        activeMenuItem:"",        tabs: [],        activeTabItem: "",      };    },    created() {},    computed: {},    components: {AsyncComponent},    methods: {      handleCollapseClick(){        this.isCollapse = !this.isCollapse        this.asideWidth = this.asideWidth=="230px"?"66px":"230px"      },      handleItemClick(item) {        let tab = this.tabs.find(tab => tab.id == item.id);        if (!tab) {          let newTab = {            id: item.id + "",            label: item.name,            closable: true,            component:item.componentPath || ""          };          this.tabs.push(newTab);        }        // activeTabItem 是绑定的name 并且要求是字符串        this.activeTabItem = item.id + "";      },      tabClick(tab) {        console.log(tab)        this.activeMenuItem = tab.name        this.activeTabItem = tab.name        },      closeTab(targetName) {        let tabs = this.tabs;        let activeTabItem = this.activeTabItem;        if(activeTabItem == targetName){          tabs.forEach((tab,index) => {            if(tab.id == targetName){              let nextTab = tabs[index-1] || tabs[index+1]              if(nextTab){                 activeTabItem = nextTab.id              }            }          })        }       this.activeTabItem = activeTabItem       this.tabs = tabs.filter(tab => tab.id != targetName)      }    },      mounted() {      this.containerHeight = window.innerHeight + "px";      $(window).resize(function() {        $("#con").height($(window).height() - 2);      });    }  };  </script>    <style>  .el-header {    background-color: #377fa9;    color: #fff;    height: 50px !important;    line-height: 50px !important;  }    .el-header .left img {    width: 120px;    vertical-align: middle;  }  .el-header .left span {    font-size: 20px;    color: #edf8ff;    margin-left: 15px;  }  .el-header .collapseBtn:hover{cursor:pointer;color:bisque;}  .el-header .right {    float: right;  }  .el-header .right a {    color: #fff;  }  .el-aside {    /* color: #32acca !important; */    background: #fff !important;    border-right:1px solid #ccc;  }  .el-menu {    border-right: none !important;    /* background: #1f3146 !important; */  }  .el-main {    padding-top: 0 !important;  }  .el-footer {    height: 40px !important;    line-height: 40px !important;    border-top: 1px solid #ccc;    background: #f8fafd;    padding: 10px;    margin-left: 0;  }  .el-footer img {    vertical-align: middle;    width: 65px;    margin-right: 10px;  }  </style>

AsyncComponent.vue

<template>      <div>        <!-- <is-loading v-if='isLoading'></is-loading>        <loading-error v-if='isError' @reload='load' :errorDetails='errorDetails'></loading-error> -->        <component :is="nowComponent"></component>      </div>  </template>    <script>  export default {    data() {      return {        nowComponent: null,      };    },    props: {      componentPath: String,    },      mounted() {      this.load();    },    methods: {      load() {          this.nowComponent = () => import(`@/components/${this.componentPath}`)      }    }  };  </script>