Vue頂部tags瀏覽歷史的實(shí)現(xiàn)
廢話
實(shí)現(xiàn)的功能
默認(rèn)有首頁,不能關(guān)閉
點(diǎn)擊路由菜單,判斷有無存在,沒有就添加,有就定位到上面
點(diǎn)擊跳轉(zhuǎn),點(diǎn)擊X可關(guān)閉
關(guān)閉當(dāng)前頁,自動(dòng)跳到下一個(gè)tag頁面
如果當(dāng)前頁在最后一個(gè),默認(rèn)跳到上一個(gè)tag頁面
右鍵菜單,刷新,關(guān)閉右側(cè),關(guān)閉所有
動(dòng)態(tài)判斷tags長多,放不下時(shí),出現(xiàn)左右兩側(cè)按鈕,減少時(shí)自動(dòng)消失
動(dòng)態(tài)判斷窗口放大縮小,自動(dòng)判斷有無左右兩側(cè)按鈕
正文
不用任何vuex,亂七八糟的方法,全在一個(gè)文件,粘貼即用
放到你想要的位置即可(此demo,放在了面包屑上面)
先安裝 (監(jiān)聽某dom元素大小的包)
npm install element-resize-detector
tags.vue
<template> <div> <div class="tags"> <!-- 左箭頭 --> <div class="arrow arrow_left" v-show="arrowVisible" @click="handleClickToLeft" > <i class="el-icon-arrow-left"></i> </div> <!-- 標(biāo)簽內(nèi)容 --> <div class="tags_content" ref="box"> <span ref="tags"> <el-tag v-for="(tag, index) in tags" :key="tag.name" :class="[active == index ? 'active top_tags' : 'top_tags']" effect="dark" :closable="tag.name != 'Firstpage1'" @close="handleClose(index, tag)" @click="clickTag(index, tag)" @contextmenu.native.prevent="handleClickContextMenu(index, tag)" > {{ $t("router." + tag.name) }} </el-tag> </span> </div> <!-- 右箭頭 --> <div class="arrow arrow_right" v-show="arrowVisible" @click="handleClickToRight" > <i class="el-icon-arrow-right"></i> </div> </div> <!-- 右鍵菜單 --> <ul v-show="contextMenu.isShow" :style="{ left: contextMenu.menuLeft, top: '96px' }" class="el-dropdown-menu el-popper" x-placement="bottom-end" > <li v-if="this.active == this.contextMenu.index" class="el-dropdown-menu__item" @click="refresh" > 刷新 </li> <li class="el-dropdown-menu__item" @click="closeRightTag"> 關(guān)閉右側(cè) </li> <li class="el-dropdown-menu__item" @click="closeOtherTag"> 關(guān)閉其它 </li> <div x-arrow="" class="popper__arrow" style="left: 44px;"></div> </ul> </div> </template> <script> import elementResizeDetectorMaker from "element-resize-detector"; export default { data() { return { // 是否有箭頭 arrowVisible: true, // 點(diǎn)擊次數(shù) num: 0, active: 0, tags: [], // 右鍵的元素 contextMenu: { index: 0, tag: {}, menuLeft: 0, isShow: false } }; }, watch: { $route() { this.getThisPage(); }, tags() { this.listenFun(this.$refs.tags, "tags"); } }, mounted() { this.listenFun(this.$refs.box, "box"); var that = this; document.addEventListener("click", function(e) { that.contextMenu.isShow = false; }); }, methods: { // 監(jiān)聽可視區(qū)域?qū)?瀏覽器窗口大小改變執(zhí)行 listenFun(monitor, dom) { let boxWidth = this.$refs.box.offsetWidth, tagsWidth = this.$refs.tags.offsetWidth, erd = elementResizeDetectorMaker(); erd.listenTo(monitor, ele => { this.$nextTick(() => { if ( (dom == "box" && ele.offsetWidth >= tagsWidth) || (dom == "tags" && ele.offsetWidth <= boxWidth) ) { this.arrowVisible = false; this.$refs.box.style.paddingLeft = "16px"; this.$refs.box.style.paddingRight = "16px"; this.$refs.box.style.transform = "TranslateX(0px)"; this.num = 0; } else { this.arrowVisible = true; this.$refs.box.style.paddingLeft = "56px"; this.$refs.box.style.paddingRight = "56px"; } }); }); }, // 判斷當(dāng)前頁 getThisPage() { let currentPgae = this.$route; // 判斷tags里是否有當(dāng)前頁面 var index = this.tags.findIndex(tag => tag.name == currentPgae.name); if (index == -1) { this.tags.push({ name: currentPgae.name, path: currentPgae.path }); } // 當(dāng)前選擇頁 this.active = this.tags.findIndex(tag => tag.name == currentPgae.name); }, // 關(guān)閉標(biāo)簽 handleClose(index, tag) { this.tags.splice(this.tags.indexOf(tag), 1); if (index == this.tags.length) { this.active = index - 1; this.$router.push(this.tags[index - 1].path); } else { this.$router.push(this.tags[index].path); } }, // 點(diǎn)擊標(biāo)簽 clickTag(index, tag) { this.active = index; this.$router.push(tag.path); }, // 左側(cè)按鈕 handleClickToLeft() { if (this.num > 0) { this.num--; this.$refs.box.style.transform = `TranslateX(-${this.num * 200}px)`; } }, // 右側(cè)按鈕 handleClickToRight() { // 最后一個(gè)標(biāo)簽右測(cè)距離瀏覽器左側(cè)距離 let lastChild = document .querySelectorAll(".top_tags") [this.tags.length - 1].getBoundingClientRect().right; // 可視窗口的寬 let bodyWidth = document.body.offsetWidth; // 右側(cè)箭頭48+右側(cè)邊距16 if (bodyWidth - lastChild <= 64) { this.num++; this.$refs.box.style.transform = `TranslateX(-${this.num * 200}px)`; } }, // 右鍵 handleClickContextMenu(index, tag) { this.contextMenu.isShow = true; this.contextMenu.index = index; this.contextMenu.tag = tag; let isTag = document .querySelectorAll(".top_tags") [index].getBoundingClientRect(); this.contextMenu.menuLeft = isTag.left - 48 + isTag.width / 2 + "px"; }, // 刷新 refresh() { this.$router.go(0); }, // 關(guān)閉其他 closeOtherTag() { let tagsLin = this.tags.length, { index, tag, menuLeft } = this.contextMenu; if (index != 0) { this.tags = [ { name: "Firstpage1", path: "/First/page1" }, { name: tag.name, path: tag.path } ]; } else { this.tags = [ { name: "Firstpage1", path: "/First/page1" } ]; } this.active = index; this.$router.push(tag.path); }, // 關(guān)閉右側(cè) closeRightTag() { let tagsLin = this.tags.length, { index, tag, menuLeft } = this.contextMenu; this.tags.splice(index + 1, tagsLin - index); this.active = index; this.$router.push(tag.path); } }, created() { // 監(jiān)聽頁面刷新 window.addEventListener("beforeunload", e => { localStorage.setItem( "tagInfo", JSON.stringify({ active: this.active, tags: this.tags }) ); }); let tagInfo = localStorage.getItem("tagInfo") ? JSON.parse(localStorage.getItem("tagInfo")) : { active: 0, tags: [ { name: "Firstpage1", path: "/First/page1" } ] }; this.active = tagInfo.active; this.tags = tagInfo.tags; } }; </script> <style lang="less" scoped> /deep/.el-tag--dark { border-color: transparent; } /deep/.el-tag--dark .el-tag__close { color: #86909c; font-size: 16px; } /deep/.el-tag--dark .el-tag__close:hover { background: #e7eaf0; } .tags { position: relative; overflow: hidden; .arrow { width: 48px; text-align: center; cursor: pointer; background: #fff; position: absolute; z-index: 1; &_left { left: 0; top: 0; } &_right { right: 0; top: 0; } } &_content { transition: 0.3s; white-space: nowrap; // padding: 0 16px; } .top_tags { margin-right: 8px; cursor: pointer; background: #fff; font-size: 12px; font-weight: 400; color: #1d2129; } .top_tags:hover, .active, .arrow:hover { background: #e7eaf0; } } </style>
重點(diǎn)
需要修改的地方
currentPgae.name 是路由結(jié)構(gòu)的name,判斷有無存在,沒有就添加,有就定位到上面,根據(jù)項(xiàng)目修改
監(jiān)聽刷新時(shí),去本地存儲(chǔ) tags 和 當(dāng)前頁面的active,F(xiàn)tistpage1 改成自己的首頁即可?
到此這篇關(guān)于Vue頂部tags瀏覽歷史的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Vue頂部tags瀏覽歷史內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue實(shí)現(xiàn)商品詳情頁的評(píng)價(jià)列表功能
這篇文章主要介紹了Vue實(shí)現(xiàn)商品詳情頁的評(píng)價(jià)列表功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-09-09vue路由傳參接收以及傳參對(duì)象為對(duì)象時(shí)的問題及解決
這篇文章主要介紹了vue路由傳參接收以及傳參對(duì)象為對(duì)象時(shí)的問題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-09-09vue.js學(xué)習(xí)之UI組件開發(fā)教程
前端開發(fā)中,隨著業(yè)務(wù)的增多,出于效率的考慮,我們對(duì)于組件化開發(fā)的需求也越來越迫切。下面這篇文章主要給大家介紹了關(guān)于vue.js之UI組件開發(fā)的相關(guān)資料,文中介紹的非常詳細(xì),需要的朋友們下面來一起看看吧。2017-07-07vue項(xiàng)目如何監(jiān)聽localStorage或sessionStorage的變化
這篇文章主要介紹了vue 項(xiàng)目如何監(jiān)聽localStorage或sessionStorage的變化,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下2021-01-01iview table高度動(dòng)態(tài)設(shè)置方法
下面小編就為大家分享一篇iview table高度動(dòng)態(tài)設(shè)置方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-03-03vue項(xiàng)目查看vue版本及cli版本的實(shí)現(xiàn)方式
這篇文章主要介紹了vue項(xiàng)目查看vue版本及cli版本的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10vue+elementUI實(shí)現(xiàn)動(dòng)態(tài)面包屑
這篇文章主要為大家詳細(xì)介紹了vue+elementUI實(shí)現(xiàn)動(dòng)態(tài)面包屑,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04