ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

vue中使用keep- alive缓存机制,切换标签含有iframe标签的界面会被重新刷新的问题处理

2021-12-18 13:00:06  阅读:226  来源: 互联网

标签:vue 标签 alive keep item 缓存 iframe children


1、序言
最近工作中,项目上遇到一个这样的需求,就是在打开报表的打印预览界面时,去切换标签,切回打印预览界面的时候,要求界面不刷新。vue框架中,我们去处理此类问题,通常马上就会想到去使用vue框架中自带的keep-alive组件,所以一开始我也是去使用了keep-alive,但是发现没有达到预期效果,后面通过研究和查阅资料发现,在vue项目中加入了含有iframe的页面,在路由切换的过程中,使用keep-alive是达不到数据缓存的效果的。

2、使用keep-alive缓存不了iframe界面原因
(1)vue中的keep-alive
【1】原理:Vue 的缓存机制并不是直接存储 DOM 结构,而是将 DOM 节点抽象成了一个个 VNode节点。因此,Vue 的 keep-alive 缓存也是基于 VNode节点 而不是直接存储 DOM 节点。在需要渲染的时候从Vnode渲染到真实DOM上。
【2】参数:Keep-alive 组件提供了 include 和 exclude 两个属性,允许组件有条件的进行缓存。
  include: 字符串或正则表达式。只有匹配的组件会被缓存。
  exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。
【3】Keep-alive 组件提供了两个生命钩子函数,分别是 activated 和 deactivated 。
  activated :当页面存在缓存的时候执行该函数。
  deactivated :在页面结束时触发该方法,可清除掉滚动方法等缓存。
(2)iframe中keep-alive机制失效原因:iframe页里的内容并不属于节点的信息,所以使用keep-alive依然会重新渲染iframe内的内容。而且iframe每一次渲染就相当于打开一个新的网页窗口,即使把节点保存下来,在渲染时iframe页还是刷新的。

3、vue中实现iframe内容缓存的思路
(1)保存iframe页里的节点信息我们很难去操作,这个时候我们就该想是否能在vue的route-view节点上动些手脚。
(2)我们可以在切换不含iframe的界面时使用vue路由,在切换含iframe页的界面时利用v-show来控制显示隐藏,使iframe的节点不被删除,以此来防止界面节点被重新更新,从而达到保存iframe节点数据的效果。
具体该怎么操作呢?请继续往下看:
第一步:我们先需要修改一下路由配置,如下:

{
    path: '/printReportShow',
    component: Layout,
    redirect: '/printReportShow',
    hidden: false,
    name: 'Layout',
    children: [
      {
        path: '/printReportShow',
        iframeComponent: printReportShow,
        name: 'printReportShow',
        hidden: false,
        meta: {title: '打印预览',}
      }
    ]
  },
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
从以上代码,不难看出/printReportShow就是我们要跳转的路由地址,我们可以看到printReportShow的路由配置中组件我写的是iframeComponent而非官方教程中的component,这样造成的后果就是在 router-view 节点中渲染时,页面显示的是空白页。
第二步:修改主界面AppMain.vue(你的可能不叫这个)中的template,添加vue的内置组件component,如下:

<template>
  <section class="app-main">
    <transition name="move" mode="out-in" @enter="onEnter">
      <keep-alive :include="cachedViews">
        <router-view :key="key" />
      </keep-alive>
    </transition>
    <!--iframe页-->
    <component
      v-for="item in hasOpenComponentsArr"
      :key="item.children[0].name"
      :is="item.children[0].name"
      v-show="$route.path === item.path"
    ></component>
  </section>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
从以上代码我们可以看到,iframe节点数据在根节点App.vue渲染时,也随即跟着渲染了,但是考虑到性能原因,对此我们选择将iframe的显示做成懒加载形式的,只有在用户进入相应的页面时才触发渲染,在渲染完毕后再通过v-show去控制界面在切换时的显示与隐藏。
第三步:AppMain.vue中具体的逻辑处理

<script>
import Vue from 'vue';
export default {
  name: 'AppMain',
  computed: {
    // 实现懒加载,只渲染已经打开过(hasOpen:true)的iframe页
    hasOpenComponentsArr() {
      return this.componentsArr.filter(item => {
        return item.children[0].hasOpen
      });
    }
  },
  data() {
    return {
      componentsArr: []
    }
  },
  watch: {
    $route() {
      // 判断当前路由是否iframe页
      this.isOpenIframePage();
    }
  },
  created() {
    // 设置iframe页的数组对象
    const componentsArr = this.getComponentsArr();
    componentsArr.forEach((item) => {
      // Vue.component(item.name, item.component);
      Vue.component(item.children[0].name, item.children[0].component);
    });
    this.componentsArr = componentsArr;
    // 判断当前路由是否iframe页
    this.isOpenIframePage();
  },
  methods:{
    // 根据当前路由设置hasOpen
    isOpenIframePage() {
      const target = this.componentsArr.find(item => {
        return item.path === this.$route.path
      });
      if (target && !target.children[0].hasOpen) {
        target.children[0].hasOpen = true;
      }
    },
    // 遍历路由的所有页面,把含有iframeComponent标识的收集起来
    getComponentsArr() {
      const router = this.$router;
      const routes = router.options.routes;
      const iframeArr = []
      const singleRoutes = routes[6];
      const printReportObj = {
        name: routes[6].children[0].name,
        path: routes[6].children[0].path,
        hasOpen: false, // 是否打开过,默认false
        component: routes[6].children[0].iframeComponent // 组件文件的引用
      }
      singleRoutes.children.splice(0,1);
      singleRoutes.children.push(printReportObj);
      iframeArr.push(singleRoutes);
      return iframeArr
    }
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
备注:由于我们系统中就涉及到一个iframe界面,所以在处理上可能有些地方写死了,如果时多iframe的可以自行参考着做相应的修改。

4、拓展
由于切换标签,含iframe的component组件不会再触发路由钩子函数和生命周期函数,导致界面数据无法做更新操作,同时浏览器刷新时,界面数据会有丢失的问题,所以我们可以考虑去监听sessionStorage的值,以此来更新数据。详情可以看下面这篇文章:vue中如何实现对sessionStorage的监听。

5、结语:
在这里要特别感谢jmx164491960老哥的提供的demo,感兴趣的小伙伴可以点击此处:git-vue中实现iframe页面的数据缓存,给予了很大的帮助。
————————————————
版权声明:本文为CSDN博主「我在小楼听着风」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44490109/article/details/110191582

标签:vue,标签,alive,keep,item,缓存,iframe,children
来源: https://www.cnblogs.com/aoye-icu/p/15704814.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有