1.实现效果

2.实现原理

  • vuex,实现对当前激活项,当前tab列表,当前tab的translateX,当前缓存页,当前路由的状态管理。

  • 将vuex中的数据保存到sessionStorage中,避免页面刷新丢失,当浏览器关闭时,清空数据。

  • 通过ref定位,拿到当前窗口宽度与当前所在路由的tab标签的所有宽度,判断两者,实现对多tab超出窗口宽度的处理。

  • 当点击tab标签页的时候,获取相应的激活项,动态的实现左侧菜单栏的选中状态,用watch监听,updateActiveName和updateOpened。

  • 当关闭tab标签的时候,splice删除当前标签,若是删除的最后一项,跳转到该项的前一项页面。当长度为1时,跳转到首页。

3.主要代码

store.js

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({state: {catch_components: [],activePath: '/index',openNames: [],activeName: "",tranx: "-0",tabList: [{ path: '/index', label: '首页', name: '首页' }]},mutations: {//清空vuex数据clearTabs(state) {state.catch_components = []state.activePath = '/homepage'state.openNames = []state.activeName = ""state.tranx = "-0"state.tabList = [{ path: '/homepage', label: '首页', name: 'home' }]},// 跳转页面执行selectMenu(state, submenu) {var activePath = submenu.pathvar oldTabList = state.tabListvar result = oldTabList.some(item => {if (item.path === activePath) {return true}})if (!result) {oldTabList.push({path: submenu.path,name: submenu.name,label: submenu.label,index: submenu.index,subName: submenu.subName})}state.activePath = activePathstate.tabList = oldTabListstate.activeName = submenu.subName + "-" + submenu.indexstate.openNames = [submenu.subName]},// 添加keepalive缓存addKeepAliveCache(state, val) {if (val === '/homepage') {return}if (state.catch_components.indexOf(val) === -1) {state.catch_components.push(val)}},// 删除keepalive缓存removeKeepAliveCache(state, val) {let cache = state.catch_componentsfor (let i = 0; i < cache.length; i++) {if (cache[i] === val) {cache.splice(i, 1);}}state.catch_components = cache},setTranx(state, val) {console.log(val)state.tranx = val},//关闭菜单closeTab(state, val) {state.activePath = val.activePathstate.tabList = val.tabListstate.openNames = val.openNamesstate.activeName = val.activeName},// 点击标签选择菜单changeMenu(state, val) {state.activePath = val.pathstate.activeName = val.subName + "-" + val.indexstate.openNames = [val.subName]}},
})

页面代码

<Menuref="asideMenu":active-name="activeName":open-names="openNames"accordiontheme="light":style="{ width: 'auto' }":class="isCollapsed ? 'collapsed-menu' : 'menu-item'"
><MenuItem@click.native="selectMenu({ path: '/index', title: '首页' })"name="index"key="index"><Icon type="ios-paw"></Icon><span class="menuTitle">首页</span></MenuItem><Submenuv-for="(item, index) in menuMap":name="index":key="index"class="sub_title"><template slot="title"><svg class="icon" aria-hidden="true" v-if="item.fonticon"><use :xlink:href="item.fonticon"></use></svg><Icon :type="item.icon" v-else /><span class="menuTitle">{{ item.title }}</span></template><template v-if="item.children"><MenuItemv-for="(each, i) in item.children":name="index + '-' + i":key="index + '-' + i"@click.native="selectMenu(each, i, index)"><span class="menuTitle">{{ each.title }}</span></MenuItem></template></Submenu>
</Menu><Row class="head-tags"><div class="head-left left" @click="setTranx(0)"><Icon type="ios-rewind" size="30" color="#ffc0cb" /></div><div class="tags-box"><divref="tags"class="tags-box-scroll":style="{ transform: `translateX(${tranx}px)` }"><Tag:ref="'tag' + index"class="tags-item":class="{ 'tags-item-active': activePath === item.path }"v-for="(item, index) in tabList":key="index":name="item.path":closable="item.path !== '/index'"@click.native="changeMenu(item)"@on-close="handleClose(item, index)">{{ item.label }}</Tag></div></div><div class="head-left right" @click="getTrans(1)"><Icon type="ios-fastforward" size="30" color="#ffc0cb" /></div>
</Row>
computed: {...mapState({activePath: (state) => state.activePath, // 已选中菜单tabList: (state) => state.tabList, // tags菜单列表catch_components: (state) => state.catch_components, // keepalive缓存openNames: (state) => state.openNames,activeName: (state) => state.activeName,tranx: (state) => state.tranx,}),
},
watch: {openNames() {this.$nextTick(() => {this.$refs.asideMenu.updateOpened();});},activeName() {this.$nextTick(() => {this.$refs.asideMenu.updateActiveName();});},},
handleClose(tab, index) {var oldOpenNames = this.$store.state.openNames,oldActiveName = this.$store.state.activeName,oldActivePath = this.$store.state.activePath,oldTabList = this.$store.state.tabList;let length = oldTabList.length - 1;for (let i = 0; i < oldTabList.length; i++) {let item = oldTabList[i];if (item.path === tab.path) {oldTabList.splice(i, 1);}}// 删除keepAlive缓存this.$store.commit("removeKeepAliveCache", tab.path);if (tab.path !== oldActivePath) {return;}if (length === 1) {this.$store.commit("closeTab", {activePath: "/index",tabList: oldTabList,});this.$router.push({ path: oldTabList[index - 1].path });return;}if (index === length) {oldActivePath = oldTabList[index - 1].path;oldOpenNames = [oldTabList[index - 1].subName];oldActiveName =oldTabList[index - 1].subName + "-" + oldTabList[index - 1].index;this.$store.commit("closeTab", {activePath: oldActivePath,tabList: oldTabList,openNames: oldOpenNames,activeName: oldActiveName,});this.$router.push({ path: oldTabList[index - 1].path });} else {oldActivePath = oldTabList[index].path;oldOpenNames = [oldTabList[index].subName];oldActiveName =oldTabList[index].subName + "-" + oldTabList[index].index;this.$store.commit("closeTab", {activePath: oldActivePath,tabList: oldTabList,openNames: oldOpenNames,activeName: oldActiveName,});this.$router.push({ path: oldTabList[index].path });}this.getTrans(2);
},
changeMenu(item) {var oldActivePath = this.$store.state.activePath;if (oldActivePath === item.path) {return;}this.$store.commit("changeMenu", item);this.$router.push({ path: item.path });this.$nextTick(() => {this.getTrans(0);});
},
selectMenu(item, i, subName) {// 加入keepalive缓存this.$store.commit("addKeepAliveCache", item.path);var submenu = {path: item.path,name: item.title,label: item.title,index: i,subName: subName,};this.$store.commit("selectMenu", submenu);this.$router.push({ path: item.path });this.$nextTick(() => {this.getTrans(0);});
},
getTrans(e) {let width = 0;if (this.$refs.tags) {width = this.$refs.tags.clientWidth;}this.tabList.map((item, index) => {if (item.path === this.activePath) {this.currentIndex = index;}if (this.$refs[`tag${index}`] && this.$refs[`tag${index}`][0]) {this.$set(this.tabList[index],"width",this.$refs[`tag${index}`][0].$el.clientWidth + 4);}});let list = this.tabList.filter((item, index) => {return index <= this.currentIndex;});let totalWidth = list.reduce((total, currentValue) => {return total + Number(currentValue.width);}, 0);let totalAllWidth = this.tabList.reduce((total, currentValue) => {return total + Number(currentValue.width);}, 0);if (e == 0) {if (Number(width) > Number(totalWidth) || Number(width) == 0) {this.setTranx(-0);return false;}this.setTranx(Number(width) - Number(totalWidth) - 60);} else if (e == 1) {if (Number(width) > Number(totalAllWidth)) {return false;}this.setTranx(Number(width) - Number(totalAllWidth) - 60);} else {if (Number(width) > Number(totalAllWidth) &&this.$store.state.tranx < 0) {this.setTranx(-0);}}
},
setTranx(val) {this.$store.commit("setTranx", val);
},

4.完整代码,关注公众号 苏苏的bug,更多vue相关,尽在苏苏的码云如果对你有帮助,欢迎你的star+订阅!

vue实现多个tab标签页的切换与关闭相关推荐

  1. Vant Tab标签页+下拉刷新+上拉加载

    Vant Tab标签页+下拉刷新+上拉加载 <template><div class="invoicePickupBox"><div class=&q ...

  2. html tab与jQuery,js与jquery分别实现tab标签页功能的方法

    本文实例讲述了js与jquery分别实现tab标签页功能的方法.分享给大家供大家参考,具体如下: 首先列出样式和html标签 *{margin: 0;padding: 0;} #myul li {li ...

  3. php表格js特效,JavaScript表格隔行变色和Tab标签页特效示例【附jQuery版】

    本文实例讲述了JavaScript表格隔行变色和Tab标签页特效.分享给大家供大家参考,具体如下: 最近一直在看JavaScript知识,偶尔也穿插一点Jquery,感觉Jquery用起来真爽,减少了 ...

  4. 微信小程序|Tab标签页

    欢迎点击「算法与编程之美」↑关注我们! 本文首发于微信公众号:"算法与编程之美",欢迎关注,及时了解更多此系列文章. 欢迎加入团队圈子!与作者面对面!直接点击! 问题描述 在使用小 ...

  5. JavaScript面向对象—— 动态创建tab标签页

    昨天呢,介绍了js中类的概念,以及使用类创建对象的过程.今天就用js中的类实现一个小的功能,动态添加.删除标签页.emmmmm,也有点像tab栏切换,不过比tab栏切换多了添加和删除的功能. 案例说明 ...

  6. 点击链接跳转到新页面并显示对应的tab标签页切换

    原理:从页面A跳转到页面B,则在A页面中跳转页面时传值,然后在B页面中写js获取该值并做对应的操作 附:tab标签页的制作链接:https://mp.csdn.net/postedit/1010531 ...

  7. 爬虫之selenium标签页的切换

    爬虫之selenium标签页的切换 当selenium控制浏览器打开多个标签页时,如何控制浏览器在不同的标签页中进行切换呢?需要我们做以下两步: 获取所有标签页的窗口句柄    [获取窗口句柄,通过窗 ...

  8. js在打开新页面的时候用新的标签页打开并且在关闭打开的页面的时候刷新父页面的方法...

    js在打开新页面的时候用新的标签页打开并且在关闭打开的页面的时候刷新父页面的方法 1.利用window.opener.location.href这个方法. 方式:父页面 window.open('.. ...

  9. Microsoft Edge 中的ie浏览器图标、右击新标签页打开功能的关闭方法

    本篇文章主要讲解 Microsoft Edge 中的ie浏览器图标.新标签页打开功能 的关闭方法 日期:2022年1月20日 作者:任聪聪 主要现象 说明:在edge浏览器中支持ie浏览器内置打开老版 ...

最新文章

  1. 转巧用notepad++ 批量转换ansi 和 utf8
  2. pytorch 反卷积 可视化_手推反卷积
  3. 项目中除了需求外还需要知道的问题
  4. Java黑皮书课后题第2章:*2.8(当前时间)程序清单2-7给出了显示当前格林尼治时间的程序。修改这个程序,提示用户输入相对于GMT的时区偏移量,显示在这个特定时区的时间
  5. 广告行业一些常用物料的尺寸
  6. 你见过的MCU最高GPIO翻转频率是多少?
  7. java用scanner类_java中关于scanner类的详细介绍
  8. 【java】调用System.gc()会发生什么?
  9. 输入url到页面返回的过程
  10. [洛谷1533] 可怜的狗狗
  11. eclipse字体大小设置教程(eclipse主窗口和控制台字体大小设置)
  12. redo日志和undo日志
  13. 闪迪ssd plus固态硬盘不识别开卡成功,慧荣SM2246XT量产教程
  14. SpringBoot中Starters是什么
  15. 学数答题160912-导数极值点偏移
  16. java判断某个日期是当年内第几周
  17. Jmeter报错Couldn‘t save test plan to file
  18. Day04| 第四期-谷歌应用商店的App分析
  19. ios 图片加载内存尺寸_iOS内存分析上-图片加载内存分析
  20. Android 实现扑克牌动画,Android_开发_Day10_扑克游戏

热门文章

  1. 字符串转换系列三:VARIANT、COleVariant 和_variant_t
  2. 连接 蓝牙调试 MOTO360 Wear
  3. java桌球教程视频,Java桌球小游戏1 - osc_wov79fj7的个人空间 - OSCHINA - 中文开源技术交流社区...
  4. 你需要知道的前端跨域知识(同源、正向代理、反向代理、前端代理、nignx反向代理)
  5. JavaScript权威指南(原书第7版) 犀牛书
  6. 微软免费杀毒软件Morro开始测试 征求定名
  7. 中国特色的免费游戏:下流下贱下作!
  8. 2019年技术盘点微服务篇(二):青云直上云霄 | 程序员硬核评测
  9. 简单微信小程序点菜菜谱-期末大作业
  10. 知吾煮不锈钢锅全新上市!开启你的烹饪之路