vue中使用keep-alive包裹的路由页面,切换时iframe标签会重新刷新加载的处理方案

1,327 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第十一天,点击查看活动详情

题引:

最近工作中,由于是刚接手一个比较年久的项目,刚分下来的任务就是把页面的缓存失效处理了。初步看了看,路由配置那块meta确实是使用了keepAlive:true,也是用了keepAlive进行判断包裹了,其他页面的缓存都没有问题,唯独那个页面的iframe缓存失效了。后面经过查询发现,在vue项目中加入了含有iframe的页面,在路由切换的过程中,使用keep-alive是达不到数据缓存的效果的。

正文:

通过大佬的文章和官方文档发现,是因为以下的问题导致缓存失效:

失效原因

keepAlive的缓存原理:
vue 的缓存机制并不是直接存储 DOM 结构,而是将 DOM 节点抽象成了一个个 VNode节点。因此,Vue 的 keep-alive 缓存也是基于VNode节点而不是直接存储DOM 节点。在需要渲染的时候从Vnode整合渲染到真实DOM上,因此我们使用了keepAlive的页面看起来是无痛刷新的。

iframe中keep-alive机制失效原因:
iframe页里的内容并不属于节点的信息,因为它是引用了路径上的整个html,不属于自身组件的节点信息。所以使用keep-alive切换时,整个iframe都会被干掉,因此我们重新进来时会重新渲染iframe内的内容。而且iframe每一次渲染就相当于打开一个新的网页窗口,即使把节点保存下来,在渲染时iframe页还是刷新的。

解决思路

如果我们去处理keepAlive的缓存机制的话,可能想想都头疼吧,毕竟牵一发而动全身。那我们换个思路,我们可以对iframe动手动脚。因为我们知道切换的时候iframe会被干掉,那么我们如果挽留它,给它重新换个家即不放在路由切换的节点上,而是同等级节点等,那么我们切换路由页面是与它无关的。当我们重新进入使用它的页面时,把它重新追回来即添加回当前页面,那不就可以保持iframe的状态了么。 没错,这有点像vue的组件<Teleport>。下面开始上代码

例子

<template>
  <div class="iframe">
    <iframe :src="iframeSrc" frameborder="0" width="100%" height="100%" v-show="isShow" ref="ifmameRef"
      id="iframes">
    </iframe>
  </div>
</template>
<script>
export default {
  data() {
    return {
      iframeSrc: 'xxx',
      isShow: true,
      dom: ''
    }
  },
  activated() {
    // 第一次激活时,选择插入到app-main这个节点,该节点包裹keepAlive整个节点,因此不会参与节点变动
    // 如果不是第一次,则使用isShow来控制节点的展示
    // 该方法需要和position:relative/absolute进行搭配使用,因为该iframe已经不在该组件节点里,而在外面,需要通过样式调整
    if (this.dom) {
      this.isShow = true
    } else {
      document.getElementsByClassName('app-main')[0].appendChild(this.$refs.ifmameRef)
    }
  },
  deactivated() {
    // 切换退出时,使用变量赋值该iframe节点信息,并关闭iframe展示
    this.dom = this.$refs.ifmameRef
    this.isShow = false
  }
}
</script>
<style lang="scss" scoped>
.iframe {
  height: calc(100vh - 207px);
}
// 此处就是样式变动区,根据项目位置来改变即可
#iframes {
  position: absolute;
  top: 30px;
  left: 30px;
  width: calc(96%);
  height: 730px;
}
</style>

以上方法就是通过一个开关(isShow)和采用Teleport的思路来实现。