电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

Vue實現多頁簽組件

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

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

Vue實現多頁簽組件

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

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

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

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

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

<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' >關閉左邊</el-button > </li> <li> <el-button type='text' @click='closeOtherRight' :disabled='false' size='mini' >關閉右邊</el-button > </li> <li> <el-button type='text' @click='closeOther' size='mini' >關閉其他</el-button > </li> </ul> </div> </div></template><script>export default { props: { keepAliveComponentInstance: {}, //keep-alive控件實例對象 blankRouteName: { type: String, default: 'blank', }, //空白路由的name值 }, data() { return { contextMenuVisible: false, //右鍵菜單是否顯示 contextMenuLeft: 0, //右鍵菜單顯示位置 contextMenuTop: 0, //右鍵菜單顯示位置 contextMenuTargetPageRoute: null, //右鍵所指向的菜單路由 openedPageRouters: [], //已打開的路由頁面 }; }, watch: { //當路由變更時,執行打開頁面的方法 $route: { handler(v) { this.openPage(v); }, immediate: true, }, }, mounted() { //添加點擊關閉右鍵菜單 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 ); //判斷頁面是否支持不同參數多開頁面功能,如果不支持且已存在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); } } }, //點擊頁面標簽卡時 onClick(route) { if (route.fullPath !== this.$route.fullPath) { this.$router.push(route.fullPath); } }, //關閉頁面標簽時 onClose(route) { let index = this.openedPageRouters.indexOf(route); this.delPageRoute(route); if (route.fullPath === this.$route.fullPath) { //刪除頁面后,跳轉到上一頁面 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); }); } }, //關閉其他頁面 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); } }, //根據路徑獲取索引 getPageRouteIndex(fullPath) { for (let i = 0; i < this.openedPageRouters.length; i++) { if (this.openedPageRouters[i].fullPath === fullPath) { return i; } } }, //關閉左邊頁面 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--; } }, //關閉右邊頁面 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>這個組件它需要兩個屬性,一個是keepAliveComponentInstance(keep-alive的控件實例對象),blankRouteName(空白路由的名稱)

為什么我需要keep-alive的控件實例對象呢,因為這個對象里面有兩個屬性,一個是cache,一個是keys,存儲著keep-alive的緩存的數據,有了這個對象,我就能在頁簽關閉時手動刪除緩存。那這個對象怎么獲取呢,如下所示,在keep-alive所在的父頁面上的mounted事件上進行獲取(如果keep-alive跟多頁簽組件不在同一個父頁面,那可能就得借用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的控件實例對象 } }, data() { return { keepAliveComponentInstance: null, }; }};</script>

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

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

還有這個組件會根據路由對象的meta對象進行不同的配置,如下所示

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

以上就是Vue實現多頁簽組件的詳細內容,更多關于Vue實現多頁簽組件的資料請關注好吧啦網其它相關文章!

標簽: Vue
相關文章:
主站蜘蛛池模板: 手机存放柜,超市储物柜,电子储物柜,自动寄存柜,行李寄存柜,自动存包柜,条码存包柜-上海天琪实业有限公司 | 山东PE给水管厂家,山东双壁波纹管,山东钢带增强波纹管,山东PE穿线管,山东PE农田灌溉管,山东MPP电力保护套管-山东德诺塑业有限公司 | 六维力传感器_三维力传感器_二维力传感器-南京神源生智能科技有限公司 | 杭州可当科技有限公司—流量卡_随身WiFi_AI摄像头一站式解决方案 | BESWICK球阀,BESWICK接头,BURKERT膜片阀,美国SEL继电器-东莞市广联自动化科技有限公司 | 食品级焦亚硫酸钠_工业级焦亚硫酸钠_焦亚硫酸钠-潍坊邦华化工有限公司 | 粉碎机_塑料粉碎机_塑料破碎机厂家-星标机械| 药品冷藏箱厂家_低温冰箱_洁净工作台-济南欧莱博电子商务有限公司官网 | 油冷式_微型_TDY电动滚筒_外装_外置式电动滚筒厂家-淄博秉泓机械有限公司 | 酒糟烘干机-豆渣烘干机-薯渣烘干机-糟渣烘干设备厂家-焦作市真节能环保设备科技有限公司 | STRO|DTRO-STRO反渗透膜(科普)_碟滤| 福建自考_福建自学考试网 | 武汉刮刮奖_刮刮卡印刷厂_为企业提供门票印刷_武汉合格证印刷_现金劵代金券印刷制作 - 武汉泽雅印刷有限公司 | 电磁铁_推拉电磁铁_机械手电磁吸盘电磁铁厂家-广州思德隆电子公司 | 电机保护器-电动机综合保护器-上海硕吉电器有限公司 | 蒸汽热收缩机_蒸汽发生器_塑封机_包膜机_封切收缩机_热收缩包装机_真空机_全自动打包机_捆扎机_封箱机-东莞市中堡智能科技有限公司 | 安徽控制器-合肥船用空调控制器-合肥家电控制器-合肥迅驰电子厂 安徽净化板_合肥岩棉板厂家_玻镁板厂家_安徽科艺美洁净科技有限公司 | 网站优化公司_SEO优化_北京关键词百度快速排名-智恒博网络 | SDI车窗夹力测试仪-KEMKRAFT方向盘测试仪-上海爱泽工业设备有限公司 | 柴油机_柴油发电机_厂家_品牌-江苏卡得城仕发动机有限公司 | 插针变压器-家用电器变压器-工业空调变压器-CD型电抗器-余姚市中驰电器有限公司 | 体感VRAR全息沉浸式3D投影多媒体展厅展会游戏互动-万展互动 | 轻型地埋电缆故障测试仪,频响法绕组变形测试仪,静荷式卧式拉力试验机-扬州苏电 | 有声小说,听书,听小说资源库-听世界网| 流变仪-热分析联用仪-热膨胀仪厂家-耐驰科学仪器商贸 | 自进式锚杆-自钻式中空注浆锚杆-洛阳恒诺锚固锚杆生产厂家 | 巨野月嫂-家政公司-巨野县红墙安康母婴护理中心 | 江苏皓越真空设备有限公司 | 济南办公室装修-厂房装修-商铺装修-工装公司-山东鲁工装饰设计 | 全自动五线打端沾锡机,全自动裁线剥皮双头沾锡机,全自动尼龙扎带机-东莞市海文能机械设备有限公司 | 赛默飞Thermo veritiproPCR仪|ProFlex3 x 32PCR系统|Countess3细胞计数仪|371|3111二氧化碳培养箱|Mirco17R|Mirco21R离心机|仟诺生物 | 厂房出售_厂房仓库出租_写字楼招租_土地出售-中苣招商网-中苣招商网 | 贴片电容代理-三星电容-村田电容-风华电容-国巨电容-深圳市昂洋科技有限公司 | TPE_TPE热塑性弹性体_TPE原料价格_TPE材料厂家-惠州市中塑王塑胶制品公司- 中塑王塑胶制品有限公司 | 披萨石_披萨盘_电器家电隔热绵加工定制_佛山市南海区西樵南方综合保温材料厂 | 手持式线材张力计-套帽式风量罩-深圳市欧亚精密仪器有限公司 | 贵州科比特-防雷公司厂家提供贵州防雷工程,防雷检测,防雷接地,防雷设备价格,防雷产品报价服务-贵州防雷检测公司 | 威海防火彩钢板,威海岩棉复合板,威海彩钢瓦-文登区九龙岩棉复合板厂 | 公交驾校-北京公交驾校欢迎您! 工作心得_读书心得_学习心得_找心得体会范文就上学道文库 | 奇酷教育-Python培训|UI培训|WEB大前端培训|Unity3D培训|HTML5培训|人工智能培训|JAVA开发的教育品牌 | 考勤系统_考勤管理系统_网络考勤软件_政企|集团|工厂复杂考勤工时统计排班管理系统_天时考勤 |