实现缓存
1、 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页还是刷新的。
2、 解决方案
判断当前页面是普通页面还是iframe页面,让普通页面走route-view,用v-if控制显隐,让iframe走动态组件(component :is),组件指向iframe文件,用v-show控制显隐,通过v-show不销毁组件的方式,来实现缓存iframe的效果
3、核心代码
layout文件
<a-layout-content>
<!-- 非iframe页面 -->
<keep-alive :include="cacheViewString">
<router-view v-if="!isIframe" :key="getRoute" style="height:100%;" />
</keep-alive>
<!-- iframe页面 -->
<div v-show="isIframe">
<component
v-for="item in iframeList"
:key="item"
is="iframeComponentName"
v-show="isIframe && $route.path.indexOf(item) > -1"
/>
</div>
</a-layout-content>
// 指向iframe文件
import iframeComponentName from '@/views/oh/OhSystemIframe.vue';
@Component({
components: {
iframeComponentName
}
})
export default class Layout extends Vue {
iframeList:any = []; // iframe菜单集合
@Watch('$route')
onRouteChange(route:any) {
// 根据路由判断当前页面是否是iframe --> 判断规则视情况而定
this.renderIframeList(route.path)
}
renderIframeList(path:any) {
if (!path.includes('oh_iframe')) return
const notExit = this.iframeList.findIndex((item:any) => item === path) === -1
if (notExit) {
this.iframeList.push(path)
}
}
get isIframe() {
// iframe标识:当前页面是否是iframe
/**
注意:判断规则视情况而定
**/
return this.$route.path.includes('oh_iframe');
}
}
OhSystemIframe文件
<template>
<div class="peis-body__main">
<div class="peis-body">
<iframe
id="ohIframe"
:src="iframeSrc"
frameborder="0"
></iframe>
</div>
</div>
</template>
以下ts代码为拼接iframeSrc的过程,可忽略,但有一个知识点 给iframe传参:postSession()
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component({
name: 'OhSystemIframe',
components: {},
})
export default class OhSystemIframe extends Vue {
iframeSrc: any = '';
mounted() {
this.renderIframeSrc();
}
renderIframeSrc() {
/* 拼接iframe地址 */
const sysFlag = '/oh/#'; // 职业病系统标识
const query = '?systemFrom=peis'; // 增加体检系统挂载标识
let targetUrl;
// 本地环境
if (window.location.href.includes('localhost')) {
const ohHost = 'http://localhost:9528/#'; // 本地职业病项目地址 -->确保本地已启动职业病的前端项目
targetUrl = ohHost + window.location.href.split('/#/oh_iframe')[1];
} else {
// 测试环境
targetUrl = window.location.href.split('/peis/#/oh_iframe/')[0] + sysFlag + this.$route.path.split('/oh_iframe')[1];
}
this.iframeSrc = targetUrl + query;
// this.postSession(); // 给职业病iframe传参 暂时用不到
}
postSession() {
// 传参方式
const data = {
selectedSystem: { deptCode: '72', deptId: '91', deptName: '健康管理中心', orgId: '10033', sysytemId: '100000', systemName: '职业病', url: 'oh/', userSysId: '5391553094598134274', userSysName: '职业病体检主任' },
};
this.$nextTick(() => {
const iframe: any = document.getElementById('ohIframe');
iframe.onload = () => {
iframe.contentWindow.postMessage(JSON.stringify(data), '*');
};
});
}
// 接收参数方式
// window.addEventListener('message', (data: any) => {
/* 挂载系统时 接收传入的参数 */
// data
// });
}
</script>