vue项目keep-alive 点击tab标签(tagsView)缓存页面,点击左侧菜单清除单个缓存(新增源码地址)

该博客介绍了如何在Vue项目中,使用keep-alive和Vuex来实现点击左侧菜单时刷新页面缓存。主要涉及在AppMain.vue中设置keep-alive的include,以及在SidebarItem.vue中监听菜单点击事件调用delCachedView方法。通过这种方式,避免了关闭tab页面再打开时的页面加载,而是实现了动态刷新缓存页面的效果。

一、需求

vue项目中通过keep-alive做的缓存页面,正常情况下是,关闭tab页面,在重新打开就会重新加载;现在产品提了一个需求是:不需要关闭tab页面,而是点击左侧菜单的时候,tab页面重新加载

二、最终效果

在这里插入图片描述

三、解决办法

前提条件: 需要把所有页签存在vuex中,可以参考vue-element-admin项目中store有个tagsView.js文件

1、layout组件AppMain.vue页面如下:

<template>
  <section class="app-main">
    <transition name="fade-transform" mode="out-in">
      <keep-alive :include="cachedViews">
        <router-view :key="key" />
      </keep-alive>
    </transition>
  </section>
</template>

<script>
export default {
  name: 'AppMain',
  computed: {
    cachedViews () {
      return this.$store.state.tagsView.cachedViews
    },
    key () {
      return this.$route.path
    }
  }
}
</script>

<style lang="scss" scoped>
.app-main {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  width: 100%;
  background: #f0f2f5;
  position: relative;
  overflow: hidden;
}

.fixed-header + .app-main {
  padding-top: 50px;
}

</style>

<style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {
  .fixed-header {
    padding-right: 15px;
  }
}
</style>

在这里插入图片描述

2、layout组件SidebarItem.vue页面如下:

在src/layout/components/Sidebar/SidebarItem.vue页面如下设置
1、在点击左侧菜单上加一个事件(写在el-menu-item标签上@click=“open(item)”)
delCachedView方法在store下的tagsView.js文件中有(也可以直接用commit)

<template>
  <div v-if="!item.hidden">
    <template
      v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"
    >
      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
      <!-- 在点击左侧菜单上加一个事件(清除点击页面的缓存)-->
        <el-menu-item
          :index="resolvePath(onlyOneChild.path)"
          :class="{'submenu-title-noDropdown':!isNest}"
          @click="open(item)"
        >
          <item
            :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)"
            :title="onlyOneChild.meta.title"
          />
        </el-menu-item>
      </app-link>
    </template>
    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
      <template slot="title">
        <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
      </template>
      <sidebar-item
        v-for="child in item.children"
        :key="child.path"
        :is-nest="true"
        :item="child"
        :base-path="resolvePath(child.path)"
        class="nest-menu"
      />
    </el-submenu>
  </div>
</template>

<script>
import path from 'path'
import { isExternal } from '@/utils/validate'
import Item from './Item'
import AppLink from './Link'
import FixiOSBug from './FixiOSBug'
export default {
  name: 'SidebarItem',
  components: { Item, AppLink },
  mixins: [FixiOSBug],
  props: {
    // route object
    item: {
      type: Object,
      required: true
    },
    isNest: {
      type: Boolean,
      default: false
    },
    basePath: {
      type: String,
      default: ''
    }
  },
  data() {
    this.onlyOneChild = null
    return {}
  },
  methods: {
    // 点击左侧菜单清除缓存(不能解决点击自身缓存)
    open(item) {
      this.$store.dispatch('tagsView/delCachedView', item)
    },
    hasOneShowingChild(children = [], parent) {
      let showingChildren = []
      showingChildren = children ? children.filter(item => {
        if (item.hidden) {
          return false
        } else {
          // Temp set(will be used if only has one showing child)
          this.onlyOneChild = item
          return true
        }
      }) : []

      // When there is only one child router, the child router is displayed by default
      if (showingChildren.length === 1) {
        return true
      }
      // Show parent if there are no child router to display
      if (showingChildren.length === 0) {
        this.onlyOneChild = { ...parent, path: '', noShowingChildren: true }
        return true
      }
      return false
    },
    resolvePath(routePath) {
      if (isExternal(routePath)) {
        return routePath
      }
      if (isExternal(this.basePath)) {
        return this.basePath
      }
      return path.resolve(this.basePath, routePath)
    }
  }
}
</script>

3、主应用的目录结构改动的截图如下:

在这里插入图片描述

四、源码地址(乾坤—主应用(main文件夹下src的layout文件夹))

gitHub组件地址

gitee码云组件地址

五、相关文章

基于ElementUi&Antd再次封装基础组件文档

vue3+ts基于Element-plus再次封装基础组件文档

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wocwin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值