-->

vue 点击菜单动态生成Tab

2020-02-27 11:35发布

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>

 

标签: