关于vue的多页面标签功能,对于嵌套router-view缓存的最终无奈解决方法

博客探讨了在Vue项目中实现多页面标签功能时遇到的缓存问题,特别是涉及嵌套router-view的情况。作者尝试了多种方法,包括使用vue-element-admin的include和exclude属性,但都遇到了问题。最后,通过将路由改为同级并使用全局mixin的beforeRouterLeave事件配合openedPageRouters数组来管理页面缓存,实现了满意的效果,但也指出这种方法会导致地址栏短暂闪烁的副作用。
摘要由CSDN通过智能技术生成

最近写我自己的后台开发框架,要弄一个多页面标签功能,之前有试过vue-element-admin的多页面,以为很完美,就按它的思路重新写了一个,但发现还是有问题的。

vue-element-admin它用的是在keep-alive组件上使用include属性,绑定$store.state.tagsView.cachedViews,当点击菜单时,往$store.state.tagsView.cachedViews添加页面的name值,在标签卡上点击关闭后就从$store.state.tagsView.cachedViews里面把缓存的name值删除掉,这样听似乎没什么问题。但它无法很好的支持无限级别的子菜单的缓存。

目前vue-element-admin官方预览地址的菜单结构大多是一级菜单分类,下面是二级子菜单。如下图所示,它只能缓存二级子菜单,三级子菜单它缓存不了。为什么会出现这个情况呢。因为嵌套router-view的问题。

 

按vue-element-admin的路由结构,它的一级菜单,其实对应的是一个layout组件,layout里面有个router-view(称它为一级router-view)它有用keep-alive包裹着,用来放二级菜单对应的页面,所以对于二级菜单来说,它都是用同一个router-view。如果我需要创建三级菜单的话,那就需要在二级菜单目录里创建一个包含router-view(称它为二级router-view)的index.vue文件,用来放三级菜单对应的页面,那么你就会发现这个三级菜单的页面怎么也缓存不了。

因为只有一级router-view被keep-alive包裹起着缓存作用,下面的router-view它不缓存。当然我们也可以在二级的router-view也包一个keep-alive,也用include属性,但你会发现也用不了,因为还要匹配name值,就是说二级router-view的文件也得写上name值,写上name值后你发现还是用不了,因为include数组里面没有这个二级router-view的name值,所以你还得在tabsView里的addView里面做手脚,把路由所匹配到的所有路由的name值都添加到cachedViews里,然后还要在关闭时再进行处理。天啊。我想想都头痛,理论是应该是可以实现的,但会增加了很多前端代码量。

请注意!下面的方法也是有Bug的,请重点看下面的BUT开始部分

还好keep-alive还有另一个属性exclude,我马上就有思路了,而且非常简洁,默认全部页面进行缓存,所有的router-view都包一层keep-alive,只有在点击标签卡上的关闭按钮时,往$store.state.sys.excludeViews添加关闭页面的name值,下次打开后再从excludeViews里面把页面的name值删除掉就行了,非常地简单易懂,不过最底层的页面,仍然需要写上跟路由定义时完全匹配的name值。这一步我仍然想不到有什么办法可以省略掉。

为方便代码,我写了一个组件aliveRouterView组件,并合局注册,这个组件用来代替router-view组件,如下面代码所示,$store.state.sys.config.PAGE_TABS这个值是是否开户多页面标签功能参数

<template>
  <keep-alive :exclude="exclude">
    <router-view />
  </keep-alive>
</template>
<script>
export default {
  computed: {
    exclude() {
      if (this.$store.state.sys.config.PAGE_TABS) {
        return this.$store.state.sys.excludeViews;
      } else {
        return /.*/;
      }
    }
  }
};
</script>

多页面标签组件viewTabs.vue,如下面代码所示

<template>
  <div class="__common-layout-tabView">
    <el-scrollbar>
      <div class="__tabs">
        <div
          class="__tab-item"
          :class="{ '__is-active':item.name==$route.name }"
          v-for="item in viewRouters"
          :key="item.path"
          @click="onClick(item)"
        >
          {
   {item.meta.title}}
          <span
            class="el-icon-close"
            @click.stop="onClose(item)"
            :style="viewRouters.length<=1?'width:0;':''"
          ></span>
        </div>
      </div>
    </el-scrollbar>
  </div>
</template>
<script>
export default {
  data() {
    return {
      viewRouters: []
    };
  },
  watch: {
    $route: {
      handler(v) {
        if (!this.viewRouters.some(item => item.name == v.name)) {
          this.viewRouters.push(v);
        }
      },
      immediate: true
    }
  },
  methods: {
    onClick(data) {
      if (this.$route.fullPath != data.fullPath) {
        this.$router.push(data.fullPath);
      }
    },
    onClose(data) {
      let index = this.viewRouters.indexOf(data);
      if (index >= 0) {
        this.viewRouters.splice(index, 1);
        if (data.name == this.$route.name) {
          this.$router.push(this.viewRouter
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值