欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2021年01月14日 11:37:37   作者:菜工  
這篇文章主要介紹了Vue實(shí)現(xiàn)多頁(yè)簽組件的方法,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下

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

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

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

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

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

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

<template>
 <div class="__common-layout-pageTabs">
  <el-scrollbar>
   <div class="__tabs">
    <div
     class="__tab-item"
     v-for="item in openedPageRouters"
     :class="{
      '__is-active': item.fullPath == $route.fullPath,
     }"
     :key="item.fullPath"
     @click="onClick(item)"
     @contextmenu.prevent="showContextMenu($event, item)"
    >
     {{ item.meta.title }}
     <span
      class="el-icon-close"
      @click.stop="onClose(item)"
      @contextmenu.prevent.stop=""
      :style="openedPageRouters.length <= 1 ? 'width:0;' : ''"
     ></span>
    </div>
   </div>
  </el-scrollbar>
  <div v-show="contextMenuVisible">
   <ul
    :style="{ left: contextMenuLeft + 'px', top: contextMenuTop + 'px' }"
    class="__contextmenu"
   >
    <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í)例對(duì)象
  blankRouteName: {
   type: String,
   default: "blank",
  }, //空白路由的name值
 },
 data() {
  return {
   contextMenuVisible: false, //右鍵菜單是否顯示
   contextMenuLeft: 0, //右鍵菜單顯示位置
   contextMenuTop: 0, //右鍵菜單顯示位置
   contextMenuTargetPageRoute: null, //右鍵所指向的菜單路由
   openedPageRouters: [], //已打開(kāi)的路由頁(yè)面
  };
 },
 watch: {
  //當(dāng)路由變更時(shí),執(zhí)行打開(kāi)頁(yè)面的方法
  $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: {
  //打開(kāi)頁(yè)面
  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
    );
    //判斷頁(yè)面是否支持不同參數(shù)多開(kāi)頁(yè)面功能,如果不支持且已存在path值一樣的頁(yè)面路由,那就替換它
    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)擊頁(yè)面標(biāo)簽卡時(shí)
  onClick(route) {
   if (route.fullPath !== this.$route.fullPath) {
    this.$router.push(route.fullPath);
   }
  },
  //關(guān)閉頁(yè)面標(biāo)簽時(shí)
  onClose(route) {
   let index = this.openedPageRouters.indexOf(route);
   this.delPageRoute(route);
   if (route.fullPath === this.$route.fullPath) {
    //刪除頁(yè)面后,跳轉(zhuǎn)到上一頁(yè)面
    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;
  },
  //重載頁(yè)面
  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)閉其他頁(yè)面
  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)閉左邊頁(yè)面
  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)閉右邊頁(yè)面
  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);
   }
  },
  //刪除頁(yè)面
  delPageRoute(route) {
   let routeIndex = this.openedPageRouters.indexOf(route);
   if (routeIndex >= 0) {
    this.openedPageRouters.splice(routeIndex, 1);
   }
   this.delRouteCache(route.fullPath);
  },
  //刪除頁(yè)面緩存
  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í)例對(duì)象),blankRouteName(空白路由的名稱)

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

<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í)例對(duì)象
  }
 },
 data() {
  return {
   keepAliveComponentInstance: null,
  };
 }
};
</script>

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

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

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

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

以上就是Vue實(shí)現(xiàn)多頁(yè)簽組件的詳細(xì)內(nèi)容,更多關(guān)于Vue實(shí)現(xiàn)多頁(yè)簽組件的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue中$set的使用(結(jié)合在實(shí)際應(yīng)用中遇到的坑)

    vue中$set的使用(結(jié)合在實(shí)際應(yīng)用中遇到的坑)

    這篇文章主要介紹了vue中$set的使用(結(jié)合在實(shí)際應(yīng)用中遇到的坑),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • Vue2?的?diff?算法規(guī)則原理詳解

    Vue2?的?diff?算法規(guī)則原理詳解

    這篇文章主要介紹了Vue2的diff算法規(guī)則原理詳解,diff?算法,就是通過(guò)比對(duì)新舊兩個(gè)虛擬節(jié)點(diǎn)不一樣的地方,針對(duì)那些不一樣的地方進(jìn)行新增或更新或刪除操作。接下來(lái)我們?cè)敿?xì)介紹節(jié)點(diǎn)更新的過(guò)程
    2022-06-06
  • vue $attrs和$listeners的使用與區(qū)別

    vue $attrs和$listeners的使用與區(qū)別

    本文主要介紹了vue $attrs和$listeners的使用與區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • vue 動(dòng)態(tài)添加class,三個(gè)以上的條件做判斷方式

    vue 動(dòng)態(tài)添加class,三個(gè)以上的條件做判斷方式

    這篇文章主要介紹了vue 動(dòng)態(tài)添加class,三個(gè)以上的條件做判斷方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • vue3發(fā)送驗(yàn)證碼倒計(jì)時(shí)功能的實(shí)現(xiàn)(防止連點(diǎn)、封裝復(fù)用)

    vue3發(fā)送驗(yàn)證碼倒計(jì)時(shí)功能的實(shí)現(xiàn)(防止連點(diǎn)、封裝復(fù)用)

    這篇文章主要介紹了vue3發(fā)送驗(yàn)證碼倒計(jì)時(shí)功能的實(shí)現(xiàn)(防止連點(diǎn)、封裝復(fù)用),實(shí)現(xiàn)思路是點(diǎn)擊發(fā)送驗(yàn)證碼,驗(yàn)證碼倒計(jì)時(shí),校驗(yàn)手機(jī)號(hào)是否正常等一系列操作,本文通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • 如何解決Element UI中NavMenu折疊菜單的坑

    如何解決Element UI中NavMenu折疊菜單的坑

    這篇文章主要介紹了如何解決Element UI中NavMenu折疊菜單的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 基于axios封裝fetch方法及調(diào)用實(shí)例

    基于axios封裝fetch方法及調(diào)用實(shí)例

    下面小編就為大家分享一篇基于axios封裝fetch方法及調(diào)用實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • vue中利用iscroll.js解決pc端滾動(dòng)問(wèn)題

    vue中利用iscroll.js解決pc端滾動(dòng)問(wèn)題

    這篇文章主要介紹了vue中利用iscroll.js解決pc端滾動(dòng)問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • vue-cli3.0 axios跨域請(qǐng)求代理配置方式及端口修改

    vue-cli3.0 axios跨域請(qǐng)求代理配置方式及端口修改

    這篇文章主要介紹了vue-cli3.0 axios跨域請(qǐng)求代理配置方式及端口修改,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • Vue 搭建Vuex環(huán)境詳解

    Vue 搭建Vuex環(huán)境詳解

    這篇文章主要為大家介紹了Vue搭建Vuex環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2021-11-11

最新評(píng)論