vue實(shí)現(xiàn)多個(gè)tab標(biāo)簽頁的切換與關(guān)閉詳細(xì)代碼
1.實(shí)現(xiàn)效果
2.實(shí)現(xiàn)原理
vuex,實(shí)現(xiàn)對(duì)當(dāng)前激活項(xiàng),當(dāng)前tab列表,當(dāng)前tab的translateX,當(dāng)前緩存頁,當(dāng)前路由的狀態(tài)管理。
將vuex中的數(shù)據(jù)保存到sessionStorage中,避免頁面刷新丟失,當(dāng)瀏覽器關(guān)閉時(shí),清空數(shù)據(jù)。
通過ref定位,拿到當(dāng)前窗口寬度與當(dāng)前所在路由的tab標(biāo)簽的所有寬度,判斷兩者,實(shí)現(xiàn)對(duì)多tab超出窗口寬度的處理。
當(dāng)點(diǎn)擊tab標(biāo)簽頁的時(shí)候,獲取相應(yīng)的激活項(xiàng),動(dòng)態(tài)的實(shí)現(xiàn)左側(cè)菜單欄的選中狀態(tài),用watch監(jiān)聽,updateActiveName和updateOpened。
當(dāng)關(guān)閉tab標(biāo)簽的時(shí)候,splice刪除當(dāng)前標(biāo)簽,若是刪除的最后一項(xiàng),跳轉(zhuǎn)到該項(xiàng)的前一項(xiàng)頁面。當(dāng)長(zhǎng)度為1時(shí),跳轉(zhuǎn)到首頁。
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數(shù)據(jù) clearTabs(state) { state.catch_components = [] state.activePath = '/homepage' state.openNames = [] state.activeName = "" state.tranx = "-0" state.tabList = [ { path: '/homepage', label: '首頁', name: 'home' } ] }, // 跳轉(zhuǎn)頁面執(zhí)行 selectMenu(state, submenu) { var activePath = submenu.path var oldTabList = state.tabList var 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 = activePath state.tabList = oldTabList state.activeName = submenu.subName + "-" + submenu.index state.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_components for (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 }, //關(guān)閉菜單 closeTab(state, val) { state.activePath = val.activePath state.tabList = val.tabList state.openNames = val.openNames state.activeName = val.activeName }, // 點(diǎn)擊標(biāo)簽選擇菜單 changeMenu(state, val) { state.activePath = val.path state.activeName = val.subName + "-" + val.index state.openNames = [val.subName] } }, })
頁面代碼
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); },
<Menu ref="asideMenu" :active-name="activeName" :open-names="openNames" accordion theme="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> <Submenu v-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" rel="external nofollow" ></use> </svg> <Icon :type="item.icon" v-else /> <span class="menuTitle">{{ item.title }}</span> </template> <template v-if="item.children"> <MenuItem v-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"> <div ref="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>
總結(jié)
到此這篇關(guān)于vue實(shí)現(xiàn)多個(gè)tab標(biāo)簽頁的切換與關(guān)閉的文章就介紹到這了,更多相關(guān)vue多個(gè)tab標(biāo)簽頁切換關(guān)閉內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
查找Vue中下標(biāo)的操作(some和findindex)
這篇文章主要介紹了查找Vue中下標(biāo)的操作(some和findindex),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08Vue組件庫ElementUI實(shí)現(xiàn)表格加載樹形數(shù)據(jù)教程
這篇文章主要為大家詳細(xì)介紹了Vue組件庫ElementUI實(shí)現(xiàn)表格加載樹形數(shù)據(jù)教程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06vue獲取token實(shí)現(xiàn)token登錄的示例代碼
最近新做了個(gè)vue項(xiàng)目,正好項(xiàng)目中有登錄部分,本文就詳細(xì)的介紹一下登錄部分的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),感興趣的小伙伴們可以參考一下2021-11-11vue使用keep-alive進(jìn)行組件緩存方法詳解(組件不緩存問題解決)
keep-alive包裹動(dòng)態(tài)組件時(shí),會(huì)緩存不活動(dòng)的組件實(shí)例,而不是銷毀它們,下面這篇文章主要給大家介紹了關(guān)于vue使用keep-alive進(jìn)行組件緩存方法(組件不緩存問題解決)的相關(guān)資料,需要的朋友可以參考下2022-09-09vue-loader和webpack項(xiàng)目配置及npm錯(cuò)誤問題的解決
這篇文章主要介紹了vue-loader和webpack項(xiàng)目配置及npm錯(cuò)誤問題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07