注意 this.$refs.tabs[i] 的属性对应
参考的原帖貌似是没对应好。
本人在使用时出现几个问题:
- title无法显示
- 只能添加一个tab
- tab会重复添加
- 默认打开的首页也能再创建
- 修改之后,功能正常。
<template>
<el-tabs v-model="activeTab" type="card"
@tab-remove="removeTab" @tab-click="tabClick">
<el-tab-pane v-for="(item, index) in tabsItem"
:key="item.name"
:label="item.title"
:name="item.name"
:closable="item.closable"
:ref="item.ref">
</el-tab-pane>
</el-tabs>
</template>
<script>
export default {
name: "Tabs",
data() {
return {
activeTab: '1', //默认显示的tab
tabIndex: 1, //tab目前显示数
tabsItem: [{
title: '库存预警',
name: '1',
closable: false,
ref: 'tabs',
}],
tabsPath: [{
name: "1",
path: '/index'
}]
}
},
watch: {
// 监听路由的变化,动态生成tabs
'$route': function (to) {
// 判断是否需要新增页面
let flag = true;
const path = to.path;
if (Object.keys(to.meta).length !== 0) {
for (let i = 0; i < this.$refs.tabs.length; i++) {
// 如果页面已存在,则直接定位当页面,否则新增tab页面
if (this.$refs.tabs[i].label === to.meta.title) {
//定位到已打开页面
this.activeTab = this.$refs.tabs[i].name;
flag = false;
break;
}
}
// 新增页面
if (flag) {
// 获得路由元数据的name和组件名
const thisName = to.meta.title
// const thisComp = to.meta.comp
//对tabs的当前激活下标和tabs数量进行自加
let newActiveIndex = ++this.tabIndex + '';
// 动态双向追加tabs
this.tabsItem.push({
title: thisName,
name: String(newActiveIndex),
closable: true,
ref: 'tabs',
})
this.activeTab = newActiveIndex;
// 后面需要得到当前tabs的时候可以通过当前tabs的name获得path
if (this.tabsPath.indexOf(path) === -1) {
this.tabsPath.push({
name: newActiveIndex,
path: path
})
}
}
}
}
},
methods: {
removeTab(targetName) { //删除Tab
let tabs = this.tabsItem; //当前显示的tab数组
let activeName = this.activeTab; //点前活跃的tab
//如果当前tab正活跃 被删除时执行
if (activeName === targetName) {
tabs.forEach((tab, index) => {
if (tab.name === targetName) {
let nextTab = tabs[index + 1] || tabs[index - 1];
if (nextTab) {
activeName = nextTab.name;
this.tabClick(nextTab);
}
}
});
}
this.activeTab = activeName;
this.tabsItem = tabs.filter(tab => tab.name !== targetName);
//在tabsPath中删除当前被删除tab的path
this.tabsPath = this.tabsPath.filter(item => item.name !== targetName)
},
tabClick(thisTab) {
/*
* thisTab:当前选中的tabs的实例
* 通过当前选中tabs的实例获得当前实例的path 重新定位路由
* */
let val = this.tabsPath.filter(item => thisTab.name === item.name)
this.$router.push({
path: val[0].path
})
}
},
mounted() {
/*
* 监听页面刷新事件
* 页面刷新前 需要保存当前打开的tabs的位置,刷新后按刷新前的顺序展示
* 使用js的sessionStorage保存刷新页面前的数据
* */
window.addEventListener('beforeunload', e => {
sessionStorage.setItem("tabsItem", JSON.stringify({
currTabsItem: this.tabsItem.filter(item => item.name !== "1"),
currTabsPath: this.tabsPath.filter(item => item.name !== "1"),
currActiveTabs: this.activeTab,
currIndex: this.tabIndex
}))
});
},
created() {
// 使用js的sessionStorage读取刷新前的数据,并按刷新前的tabs顺序重新生成tabs
const sessionTabs = JSON.parse(sessionStorage.getItem("tabsItem"))
if (sessionTabs.currTabsItem.length !== 0 && sessionTabs.currTabsPath.length !== 0) {
for (let i = 0; i < sessionTabs.currTabsItem.length; i++) {
this.tabsItem.push({
title: sessionTabs.currTabsItem[i].title,
name: sessionTabs.currTabsItem[i].name,
closable: true,
ref: sessionTabs.currTabsItem[i].ref,
content: sessionTabs.currTabsItem[i].content
})
}
for (let j = 0; j < sessionTabs.currTabsPath.length; j++) {
this.tabsPath.push({
name: sessionTabs.currTabsPath[j].name,
path: sessionTabs.currTabsPath[j].path
})
}
this.activeTab = sessionTabs.currActiveTabs
this.tabIndex = sessionTabs.currIndex
// 避免强制修改url 出现浏览器的url输入框的路径和当前tabs选中的路由路径不匹配
const activePath = this.tabsPath.filter(item => item.name === this.activeTab)
this.$router.push({
path: activePath[0].path
})
}
},
}
</script>
<style scoped>
/deep/ .el-tabs__header {
margin: 0;
}
</style>