日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

Vue實(shí)現(xiàn)多頁簽組件

瀏覽:26日期:2022-10-10 15:58:59

直接看效果,增加了右鍵菜單,分別有重新加載、關(guān)閉左邊、關(guān)閉右邊、關(guān)閉其他功能。

Vue實(shí)現(xiàn)多頁簽組件

也可以到我的github上看看代碼(如果覺得這個(gè)組件有用的話,別忘了順手給個(gè)小星星)

代碼:https://github.com/Caijt/VuePageTab

演示:https://caijt.github.io/VuePageTab/

我這個(gè)多頁簽組件里面的刪除緩存的方法不是使用keep-alive組件自帶的include、exculde結(jié)合的效果,而是使用暴力刪除緩存的方法,這個(gè)在上個(gè)博客中也有提到,用這種方法的話,可以實(shí)現(xiàn)更完整的多頁簽功能,例如同個(gè)路由可以根據(jù)參數(shù)的不同同時(shí)打開不同的頁簽,也能不用去寫那些路由的name值。

先直接看組件代碼(里面用了一些element-ui的組件,如果你們不用element-ui的話。可以去掉,自己實(shí)現(xiàn))

<template> <div class='__common-layout-pageTabs'> <el-scrollbar> <div class='__tabs'> <div v-for='item in openedPageRouters' : :key='item.fullPath' @click='onClick(item)' @contextmenu.prevent='showContextMenu($event, item)' > {{ item.meta.title }} <span @click.stop='onClose(item)' @contextmenu.prevent.stop='' : ></span> </div> </div> </el-scrollbar> <div v-show='contextMenuVisible'> <ul : > <li> <el-button type='text' @click='reload()' size='mini'> 重新加載 </el-button> </li> <li> <el-button type='text' @click='closeOtherLeft' :disabled='false' size='mini' >關(guān)閉左邊</el-button > </li> <li> <el-button type='text' @click='closeOtherRight' :disabled='false' size='mini' >關(guān)閉右邊</el-button > </li> <li> <el-button type='text' @click='closeOther' size='mini' >關(guān)閉其他</el-button > </li> </ul> </div> </div></template><script>export default { props: { keepAliveComponentInstance: {}, //keep-alive控件實(shí)例對象 blankRouteName: { type: String, default: 'blank', }, //空白路由的name值 }, data() { return { contextMenuVisible: false, //右鍵菜單是否顯示 contextMenuLeft: 0, //右鍵菜單顯示位置 contextMenuTop: 0, //右鍵菜單顯示位置 contextMenuTargetPageRoute: null, //右鍵所指向的菜單路由 openedPageRouters: [], //已打開的路由頁面 }; }, watch: { //當(dāng)路由變更時(shí),執(zhí)行打開頁面的方法 $route: { handler(v) { this.openPage(v); }, immediate: true, }, }, mounted() { //添加點(diǎn)擊關(guān)閉右鍵菜單 window.addEventListener('click', this.closeContextMenu); }, destroyed() { window.removeEventListener('click', this.closeContextMenu); }, methods: { //打開頁面 openPage(route) { if (route.name == this.blankRouteName) { return; } let isExist = this.openedPageRouters.some( (item) => item.fullPath == route.fullPath ); if (!isExist) { let openedPageRoute = this.openedPageRouters.find( (item) => item.path == route.path ); //判斷頁面是否支持不同參數(shù)多開頁面功能,如果不支持且已存在path值一樣的頁面路由,那就替換它 if (!route.meta.canMultipleOpen && openedPageRoute != null) { this.delRouteCache(openedPageRoute.fullPath); this.openedPageRouters.splice( this.openedPageRouters.indexOf(openedPageRoute), 1, route ); } else { this.openedPageRouters.push(route); } } }, //點(diǎn)擊頁面標(biāo)簽卡時(shí) onClick(route) { if (route.fullPath !== this.$route.fullPath) { this.$router.push(route.fullPath); } }, //關(guān)閉頁面標(biāo)簽時(shí) onClose(route) { let index = this.openedPageRouters.indexOf(route); this.delPageRoute(route); if (route.fullPath === this.$route.fullPath) { //刪除頁面后,跳轉(zhuǎn)到上一頁面 this.$router.replace( this.openedPageRouters[index == 0 ? 0 : index - 1] ); } }, //右鍵顯示菜單 showContextMenu(e, route) { this.contextMenuTargetPageRoute = route; this.contextMenuLeft = e.layerX; this.contextMenuTop = e.layerY; this.contextMenuVisible = true; }, //隱藏右鍵菜單 closeContextMenu() { this.contextMenuVisible = false; this.contextMenuTargetPageRoute = null; }, //重載頁面 reload() { this.delRouteCache(this.contextMenuTargetPageRoute.fullPath); if (this.contextMenuTargetPageRoute.fullPath === this.$route.fullPath) { this.$router.replace({ name: this.blankRouteName }).then(() => { this.$router.replace(this.contextMenuTargetPageRoute); }); } }, //關(guān)閉其他頁面 closeOther() { for (let i = 0; i < this.openedPageRouters.length; i++) { let r = this.openedPageRouters[i]; if (r !== this.contextMenuTargetPageRoute) { this.delPageRoute(r); i--; } } if (this.contextMenuTargetPageRoute.fullPath != this.$route.fullPath) { this.$router.replace(this.contextMenuTargetPageRoute); } }, //根據(jù)路徑獲取索引 getPageRouteIndex(fullPath) { for (let i = 0; i < this.openedPageRouters.length; i++) { if (this.openedPageRouters[i].fullPath === fullPath) { return i; } } }, //關(guān)閉左邊頁面 closeOtherLeft() { let index = this.openedPageRouters.indexOf( this.contextMenuTargetPageRoute ); let currentIndex = this.getPageRouteIndex(this.$route.fullPath); if (index > currentIndex) { this.$router.replace(this.contextMenuTargetPageRoute); } for (let i = 0; i < index; i++) { let r = this.openedPageRouters[i]; this.delPageRoute(r); i--; index--; } }, //關(guān)閉右邊頁面 closeOtherRight() { let index = this.openedPageRouters.indexOf( this.contextMenuTargetPageRoute ); let currentIndex = this.getPageRouteIndex(this.$route.fullPath); for (let i = index + 1; i < this.openedPageRouters.length; i++) { let r = this.openedPageRouters[i]; this.delPageRoute(r); i--; } if (index < currentIndex) { this.$router.replace(this.contextMenuTargetPageRoute); } }, //刪除頁面 delPageRoute(route) { let routeIndex = this.openedPageRouters.indexOf(route); if (routeIndex >= 0) { this.openedPageRouters.splice(routeIndex, 1); } this.delRouteCache(route.fullPath); }, //刪除頁面緩存 delRouteCache(key) { let cache = this.keepAliveComponentInstance.cache; let keys = this.keepAliveComponentInstance.keys; for (let i = 0; i < keys.length; i++) { if (keys[i] == key) { keys.splice(i, 1); if (cache[key] != null) { delete cache[key]; } break; } } }, },};</script><style lang='scss'>.__common-layout-pageTabs { .__contextmenu { // width: 100px; margin: 0; border: 1px solid #e4e7ed; background: #fff; z-index: 3000; position: absolute; list-style-type: none; padding: 5px 0; border-radius: 4px; font-size: 14px; color: #333; box-shadow: 1px 1px 3px 0 rgba(0, 0, 0, 0.1); li { margin: 0; padding: 0px 15px; &:hover { background: #f2f2f2; cursor: pointer; } button { color: #2c3e50; } } } $c-tab-border-color: #dcdfe6; position: relative; &::before { content: ''; border-bottom: 1px solid $c-tab-border-color; position: absolute; left: 0; right: 0; bottom: 0; height: 100%; } .__tabs { display: flex; .__tab-item { white-space: nowrap; padding: 8px 6px 8px 18px; font-size: 12px; border: 1px solid $c-tab-border-color; border-left: none; border-bottom: 0px; line-height: 14px; cursor: pointer; transition: color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1), padding 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); &:first-child { border-left: 1px solid $c-tab-border-color; border-top-left-radius: 2px; margin-left: 10px; } &:last-child { border-top-right-radius: 2px; margin-right: 10px; } &:not(.__is-active):hover { color: #409eff; .el-icon-close { width: 12px; margin-right: 0px; } } &.__is-active { padding-right: 12px; border-bottom: 1px solid #fff; color: #409eff; .el-icon-close { width: 12px; margin-right: 0px; margin-left: 2px; } } .el-icon-close { width: 0px; height: 12px; overflow: hidden; border-radius: 50%; font-size: 12px; margin-right: 12px; transform-origin: 100% 50%; transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1); vertical-align: text-top; &:hover { background-color: #c0c4cc; color: #fff; } } } }}</style>這個(gè)組件它需要兩個(gè)屬性,一個(gè)是keepAliveComponentInstance(keep-alive的控件實(shí)例對象),blankRouteName(空白路由的名稱)

為什么我需要keep-alive的控件實(shí)例對象呢,因?yàn)檫@個(gè)對象里面有兩個(gè)屬性,一個(gè)是cache,一個(gè)是keys,存儲著keep-alive的緩存的數(shù)據(jù),有了這個(gè)對象,我就能在頁簽關(guān)閉時(shí)手動刪除緩存。那這個(gè)對象怎么獲取呢,如下所示,在keep-alive所在的父頁面上的mounted事件上進(jìn)行獲取(如果keep-alive跟多頁簽組件不在同一個(gè)父頁面,那可能就得借用vuex來傳值了)

<template> <div id='app'> <page-tabs :keep-alive-component-instance='keepAliveComponentInstance' /> <div ref='keepAliveContainer'> <keep-alive> <router-view :key='$route.fullPath' /> </keep-alive> </div> </div></template><script>import pageTabs from './components/pageTabs.vue';export default { name: 'App', components: { pageTabs, }, mounted() { if (this.$refs.keepAliveContainer) { this.keepAliveComponentInstance = this.$refs.keepAliveContainer.childNodes[0].__vue__;//獲取keep-alive的控件實(shí)例對象 } }, data() { return { keepAliveComponentInstance: null, }; }};</script>

而空白路由的名稱,是干什么,主要我要實(shí)現(xiàn)刷新當(dāng)前頁面的功能,我們知道vue是不允許跳轉(zhuǎn)到當(dāng)前頁面,那么我就想我先跳轉(zhuǎn)到別的頁面,再跳轉(zhuǎn)回回來的頁面,不就也實(shí)現(xiàn)刷新的效果了。(當(dāng)然我用的是relpace,所以不會產(chǎn)生歷史記錄)

注:這個(gè)空白路由并不是固定定義在根路由上,需根據(jù)多頁簽組件所在位置,假如你有一個(gè)根router-view,還有一個(gè)布局組件,這個(gè)組件里面也有一個(gè)子router-view,多頁簽組件就在這個(gè)布局組件里,那么空白路由就需定義在布局組件對應(yīng)的路由的children里面了

還有這個(gè)組件會根據(jù)路由對象的meta對象進(jìn)行不同的配置,如下所示

let router = new Router({ routes: [ //這個(gè)是空白頁面,重新加載當(dāng)前頁面會用到 { name: 'blank', path: '/blank', }, { path: '/a', component: A, meta: { title: 'A頁面', //頁面標(biāo)題 canMultipleOpen: true //支持根據(jù)參數(shù)不同多開不同頁簽,如果你需要/a跟/a?v=123都分別打開兩個(gè)頁簽,請?jiān)O(shè)置為true,否則就只會顯示一個(gè)頁簽,后打開的會替換到前打開的頁簽 } }}

以上就是Vue實(shí)現(xiàn)多頁簽組件的詳細(xì)內(nèi)容,更多關(guān)于Vue實(shí)現(xiàn)多頁簽組件的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Vue
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲精品午夜av福利久久蜜桃| 久久一区二区中文字幕| 日韩在线短视频| 欧美一级二区| 石原莉奈在线亚洲二区| 欧美精品一卡| 日韩精品久久久久久久电影99爱| 久久一区视频| 日韩中文字幕av电影| 国产专区一区| 亚洲一级特黄| 欧美日一区二区| 日韩一区自拍| 国产成人精品一区二区三区视频| 国产精品视频一区二区三区综合| 日本一区二区三区视频在线看| 午夜宅男久久久| 亚洲国产成人精品女人| 91tv亚洲精品香蕉国产一区| 深夜福利视频一区二区| 国产传媒av在线| 日产精品一区二区| 成人一区而且| 国产一区二区三区日韩精品| 久久影视三级福利片| 国产精品亚洲产品| 国产精品白丝一区二区三区| 日韩免费精品| 午夜在线视频观看日韩17c| 激情五月综合网| 蜜桃成人av| 亚洲激情五月| 亚洲二区三区不卡| 久热re这里精品视频在线6| 亚洲专区欧美专区| 尹人成人综合网| 99香蕉国产精品偷在线观看| 亚洲欧美成人综合| 国产精品97| 香蕉精品999视频一区二区| 日韩中文字幕av电影| 美国三级日本三级久久99 | 日韩三级视频| 国产精品天天看天天狠| 九九精品调教| 少妇高潮一区二区三区99| 国产精品国产三级国产在线观看| 在线一区免费观看| 久久国产精品美女| 国产精品毛片在线| 国产一区二区三区四区二区| 136国产福利精品导航网址| 欧美影院精品| 久久亚洲精品伦理| 岛国av免费在线观看| 蜜臀久久99精品久久久久久9| 国产极品模特精品一二| 中文欧美日韩| 久久一区国产| 麻豆9191精品国产| 国产精品久久观看| 亚洲三级毛片| 天堂中文在线播放| 日韩欧美中文字幕电影| 精品国模一区二区三区| 欧美日韩黄网站| 日韩精品专区| 亚洲精品免费观看| 欧美日韩色图| 国模精品一区| 亚洲精品视频一二三区| 欧美日韩亚洲在线观看| 欧美激情精品| 亚洲开心激情| | 日韩av中文字幕一区二区| 日韩电影免费在线观看| 日韩国产欧美在线播放| 国产高清一区| 超级白嫩亚洲国产第一| 在线精品亚洲| 精品一区毛片| 欧美日韩国产观看视频| 国产欧美一区二区精品久久久| 婷婷综合网站| 97精品视频在线看| 国产精品亚洲产品| 亚洲精品黄色| 亚洲专区一区| 1000部精品久久久久久久久| 国产精品毛片久久| 久久99久久久精品欧美| 亚洲精品高潮| aa国产精品| 九一精品国产| 高清一区二区三区| 另类小说一区二区三区| 国产视频网站一区二区三区| 四虎精品一区二区免费| 亚洲视频国产精品| 国产精品社区| 一区在线观看| 五月天激情综合网| 亚洲h色精品| 色爱av综合网| 成人片免费看| 日韩免费在线| 天堂av在线| 蜜臀国产一区| 精品一二三区| 六月丁香综合在线视频| 国产精品99久久久久久董美香| 18国产精品| 欧美日韩xxxx| 国产亚洲高清一区| 97久久亚洲| 欧美日韩网址| 国产精品香蕉| 国产精品日韩精品在线播放| 日本va欧美va精品发布| 日韩精品一区二区三区免费视频| 国产精品网址| 国产经典一区| 精品一区二区三区在线观看视频 | 亚洲香蕉久久| 综合国产精品| 亚洲精品影视| 18国产精品| 国产精品网在线观看| 国产精品男女| 国产精东传媒成人av电影| 麻豆91精品视频| 国产精品成人a在线观看| zzzwww在线看片免费| 久久久久久久久99精品大| 日韩精品免费一区二区三区| 亚洲高清二区| 蜜臀久久久久久久| 日本va欧美va精品发布| 久久99久久久精品欧美| 国产aa精品| 亚洲视频综合| 亚洲欧美不卡| 欧美日韩一区自拍| 久久久免费人体| 在线一区视频观看| 久久国产精品亚洲77777| 日韩精品一区二区三区中文| 久久的色偷偷| 国产99精品| 国产亚洲毛片在线| 亚洲精品亚洲人成在线观看| 国产伦理久久久久久妇女| 精品久久国产一区| 欧美不卡在线| 日韩av字幕| 久久uomeier| 国产精品女主播一区二区三区| 91九色综合| 日韩成人a**站| 99pao成人国产永久免费视频| 日本亚洲视频在线| 久久精品天堂| 日韩视频精品在线观看| 日韩精品一区二区三区av | 91精品一区二区三区综合在线爱| 欧美一区=区| 久久国产视频网| 中文一区一区三区高中清不卡免费| 久久精品国内一区二区三区水蜜桃| 日韩制服丝袜先锋影音| 欧美a一区二区| 免费国产自久久久久三四区久久| 日韩视频一二区| 日韩电影免费网站| 在线观看一区| 国产精品蜜芽在线观看| 日韩制服丝袜av| 国产精品久久久亚洲一区| 日本精品在线中文字幕| 亚洲免费观看高清完整版在线观| 精品久久99| 亚洲一区二区三区四区五区午夜| 国产精品大片| 亚洲综合日本| 精品久久不卡| 日韩专区一卡二卡| 成人精品久久| 天堂久久一区| 亚洲大片在线| 久久不见久久见国语| 亚洲国产一区二区三区在线播放| 国产视频一区二区在线播放| 日本精品在线中文字幕| 亚洲精品成a人ⅴ香蕉片| 午夜av成人| 国产精品久久久久久久久久妞妞| 午夜久久99| 中文字幕人成乱码在线观看| 日韩专区视频网站|