前言

最近接收了一个陈年的vue2项目,经历了多个前辈高人,目前可以说是一座伟岸的shit山。如果改改bug之类的雕花需求还能接受,但是在交付后了来了一个需要腾空10米然后空中转体720平稳落地之后进行雕花的高难度需求。

对tabs页面进行缓存

需要对现有项目进行页面缓存,点击面包屑顶部的tabs标签<如下图>切换页面时保持住页面缓存,使用菜单或按钮跳转切换页面则需要进行更新(清除缓存)
在这里插入图片描述

难点

1. 菜单页面的多级缓存

解决分析

...

<keep-alive :include="cachedViews">
    <router-view :key="routeName" />
</keep-alive>

...

cachedViews() {
	// 将多级(三级)容器文件name-ThirdView 添加进include中
	return [...allCachedViews, ...['ThirdView']]
},
routeName() {
	this.$store.commit('tabsView/SET_TABFLAG', false)
    return this.$route.name
}

解决方法: 由于路由时动态渲染的,二级,三级路由都使用同一个容器文件渲染。当有三级路由需要缓存时,必须将路由容器组件加入includes中。这样三级路由缓存便可以生效。所以将三级路由使用的容器组件name加入includes即可让三级路由页面的缓存生效。
参考思路: vue 使用动态路由参数的 keep-alive 条件缓存与三级路由缓存解决


2. keep-alive通过include与key的更新无法清除旧的缓存

解决分析

因初始前辈们开发页面时未预留方案进行缓存功能实现,而如今页面巨多直接修改工作量大且容易引入新的问题,
也不便于后期维护和优化,果断放弃每个页面去进行keep-alive钩子函数的方法编写。
通过mixins在main.js中进行逻辑实现
beforeRouteLeave(to, from, next) {
    try {
      const cachedViews = this.$store.state.tabsView.cachedViews
      const tabFlag = this.$store.state.tabsView.tabFlag
      // const findInCache = cachedViews.find(v => v.includes(from.name))
      if (!tabFlag && cachedViews.includes(to.name)) { // 说明是关闭了路由或者tabs切换
        // 删除缓存
        this.$store.commit('tabsView/SET_CACHEDFLAG', true)
        this.$store.dispatch('tabsView/delTabsView', to.name)
        const keepAliveInstance = this.findKeepAlive()
        if (!keepAliveInstance) {
          return next()
        }
        const { cache } = keepAliveInstance
        const cacheKeys = Object.keys(cache)
        const delKey = cacheKeys.find(key => key.includes(to.name))
        delKey && (cache[delKey] = null)
        Reflect.deleteProperty(cache, delKey)
        // this.$destroy() // 调用组件的销毁
      }
      next()
    } catch (error) {
      next()
    }
  },

  methods: {
    // ...
    findKeepAlive() {
      const vnodeParent = this.$vnode.parent
      // console.log(this.$vnode.parent, this.$parent.$vnode.parent)
      // this.$parent.$vnode.parent
      if (vnodeParent.tag.includes('keep-alive')) {
        return vnodeParent.componentInstance
      }
      return null
    }
  },

keep-alive通过控制但实际在切换后回到页面中仍被缓存了,通过方案对比最后还是决定手动清除缓存实现。
手动操作keep-alive 看过vue源码的同学,会发现keep-alive实现会将组件存放在caches数组当中,这个时候我们对数组进行操作,这个时候,就可以做到前往其他页面的时候,该缓存还是不该缓存,这样就可以达到灵活使用。
参考思路: Vue之keep-alive灵活清除页面缓存分享


3. 三级路由切换到二级路由页面时,清除没有生效(菜单点击至二级页面仍是缓存页面)

解决分析

在断点调试中发现,二级路由与三级路由缓存的页面也不在同一层级,这就是为什么从三级路由页面切换回二级路由页面没有执行清除操作
既然在上面一个问题中找到了在 vueInstance.$vnode.parent.componentInstance 能获取到keep-alive实例,那在三级路由中也能找到二级路由的实例,通过正常逻辑分析与多次断点调试找到了上个层级的keep-alive实例需要在vueInstance后多加一层 $paren t即可找到

// 优化vnodeParent 
findKeepAlive() {
    const vnodeParent = this.$vnode.parent ? this.$vnode.parent : this.$parent.$vnode.parent
    // console.log(this.$vnode.parent, this.$parent.$vnode.parent)
    // this.$parent.$vnode.parent
    if (vnodeParent.tag.includes('keep-alive')) {
      return vnodeParent.componentInstance
    }
    return null
}

记录完结

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐