参考:https://blog.csdn.net/hjx154954264/article/details/104799141/
一、前期准备工作
1.在index.js里正常导入路由
//这里的meta的comp设置,加上单引号为字符串,如果设置为路由,后续会把路由缓存进sessionStorage,缓存里面的数据是json格式, component 是一个vue文件,所以没办法解析,会报错
2.写导航菜单navmenu(开启路由模式)
3.写tab标签页
tabs的content用组件展示
(1)导入组件
(2)
二、动态添加tabs
1 watch: { 2 $route: function (to) { 3 //监听路由的变化,动态生成tabs 4 console.log(to); 5 let flag = true; //判断是否需要新增页面 6 const path = to.path; 7 console.log(Object.keys(to.meta).length) 8 if (Object.keys(to.meta).length != 0) { 9 for (let i = 0; i < this.$refs.tabs.length; i++) { 10 if (i != 0) { 11 //首页不判断 如果页面已存在,则直接定位当页面,否则新增tab页面 12 if (this.$refs.tabs[i].label == to.meta.name) { 13 this.activeTab = this.$refs.tabs[i].name; //定位到已打开页面 14 flag = false; 15 break; 16 } 17 } 18 } 19 //新增页面 20 if (flag) { 21 //获得路由元数据的name和组件名 22 const thisName = to.meta.name; //在index.js中定义的meta 23 const thisComp = to.meta.comp; 24 //对tabs的当前激活下标和tabs数量进行自加 25 let newActiveIndex = ++this.tabIndex + ""; 26 //动态双向追加tabs 27 this.tabsItem.push({ 28 title: thisName, 29 name: String(newActiveIndex), 30 closable: true, 31 ref: "tabs", 32 content: thisComp, 33 }); 34 this.activeTab = newActiveIndex; 35 /* 36 * 当添加tabs的时候,把当前tabs的name作为key,path作为value存入tabsPath数组中 37 * ///后面需要得到当前tabs的时候可以通过当前tabs的name获得path 38 * */ 39 if (this.tabsPath.indexOf(path) == -1) { 40 this.tabsPath.push({ 41 name: newActiveIndex, 42 path: path, 43 }); 44 } 45 } 46 } 47 }, 48 },
三、用sessionstorage保存tabs(否则一刷新标签页就恢复原样,只有首页)
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, //这里不要把路由缓存进sessionStorage,因为缓存里面的数据是json格式, component 是一个vue文件,所以没办法解析,会报错(此处我的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, }); } },
四、实现删除标签页
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,
});
},