UI 组件采用element NavMenu点击左侧的菜单列表生成Tab,如下图
查看效果链接
主要思路
(1)点击菜单列表的时生成tab数据
(2)点击tab 展示当前激活tab的信息
(3)点击关闭按钮移除tab的数据,如果删除的是当前激活的tab,激活的tab前移或后移(删除tab的前一个或者后一个)
(4)采用动态组件展示每个tab的具体内容
这个例子中菜单列表没有采用路由跳转,采用路由与不采用路由跳转动态生成Tab 的原理都是一样的。
Home.vue
代码语言:javascript复制<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
代码语言:javascript复制<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>