路由组件中使用keep-alive 其他组件会正常缓存 但是含有iframe的页面无法正常缓存,这个问题困扰了我很久,也成为了项目目前的一个瓶颈。突然有一天,我们的技术总监推荐给我一篇博文,真的是让我醍醐灌顶,虽然这个keep-alive的一个问题吧,但是我们可以通过其他方式进行规避。
我们换个方式 通过v-show的方式切换含有iframe的组件
<multi-tab-store-consumer>
这个组件大家不必纠结,这个是框架自带的一个组件,忽略就可以。
- 后端给的路由属性中添加一个menuType标识页面中是否有iframe,如果有的话使用一个空的组件代替。
- 使用v-show控制其他组件的显示(在加载组件的时候循环已经打开的组件,而不是循环所有的组件,来提高渲染效率)
这里使用computed去筛选已经打开的组件 (store.cacheList是目前已经打开的页面缓存信息)
<template>
<router-view v-slot="{ Component, route }">
<transition :name="transitionName" appear>
<multi-tab-store-consumer>
<component v-if="Component" :is="Component" :pageName="route.meta.title"></component>
<slot v-else />
</multi-tab-store-consumer>
</transition>
</router-view>
<!--通过v-show的方式切换含有iframe的组件-->
<div v-if="isPageAlive" v-show="isDcPath" style="height: 100%">
<div
style="height: 100%"
v-for="item in hasOpenComponentsArr"
v-show="$route.path === item.path"
:key="item.name"
>
<component
v-if="pageAliveObj[item.path]"
:is="item.name"
:pageName="item.meta.title"
></component>
</div>
</div>
</template>
<script lang="ts">
import {
computed,
defineAsyncComponent,
defineComponent,
nextTick,
reactive,
ref,
toRefs,
watch,
} from 'vue';
import { MultiTabStoreConsumer } from '@/components/multi-tab';
import { injectMenuState } from './use-menu-state';
import localStorage from '@/utils/local-storage';
import { injectMultiTabStore } from '@/components/multi-tab/multi-tab-store';
import emitter from '@/views/EMRClient/WardNurseStationUI/DoctorOrdersTreatement/components/eventBus';
import { useRoute } from 'vue-router';
import { SET_ACCESS_CHANGE_MENU } from '@/store/modules/user/actions';
import { useStore } from 'vuex';
/**
* @Author: zpp
* @description: 获取含有iframe的 组件 参考链接: https://blog.csdn.net/weixin_44490109/article/details/110191582
* @return {*}
*/
function getIframe() {
const allowRouters = localStorage.get('allowRouters');
let iframeCom: any = {}; // 组件对象
let iframeComArr: any = []; // 组件数组 用于页面中component渲染
iframeCom['MultiTabStoreConsumer'] = MultiTabStoreConsumer;
const getIframeCom = (routers: any) => {
routers.forEach((item: any) => {
if (item.meta.menuType === '0') {
let AsyncCom = defineAsyncComponent(() => import(`@/views/` + item.iframe));
iframeCom[item.name] = AsyncCom;
iframeComArr.push({
name: item.name,
path: item.path,
meta: item.meta,
});
}
if (item.children && item.children.length > 0) {
getIframeCom(item.children);
}
});
};
if (allowRouters) {
getIframeCom(allowRouters);
}
return { iframeCom, iframeComArr };
}
const { iframeCom: myComponent, iframeComArr: myComponentArr }: any = getIframe();
export default defineComponent({
name: 'CustomRouterView',
setup() {
const route = useRoute();
const store = injectMultiTabStore();
const menuState = injectMenuState();
const store1 = useStore();
const hasOpenComponentsArr = computed(() => {
if (store) {
// (store.cacheList是目前已经打开的页面缓存信息)
let arr = store.cacheList.map((ele: any) => ele.path);
let comArr = myComponentArr.filter((item: any) => {
let loaction = arr.indexOf(item.path);
return loaction > -1;
});
return comArr;
} else {
return [];
}
});
interface PageAlive {
[key: string]: boolean;
}
let pageData = reactive({
pageAliveObj: {} as PageAlive,
isPageAlive: true, // 控制所有组件的显示
isDcPath: false,
});
myComponentArr.forEach((ele: any) => {
pageData.pageAliveObj[ele.path] = true;
});
watch(
() => route.fullPath,
() => {
let result = myComponentArr.find((element: any) => element.path === route.fullPath);
pageData.isDcPath = result !== undefined ? true : false;
},
{ immediate: true },
);
// 刷新所有的组件
emitter.on('refreshAllTab', data => {
pageData.isPageAlive = false;
//store1.dispatch(`user/${SET_ACCESS_CHANGE_MENU}`, data);
localStorage.set('changeMenu', data);
nextTick(() => {
pageData.isPageAlive = true;
});
});
// 刷新某一个组件
emitter.on('refreshOneTab', (data: any) => {
pageData.pageAliveObj[data] = false;
nextTick(() => {
pageData.pageAliveObj[data] = true;
});
});
return {
transitionName: computed(() => menuState.transitionName.value),
hasOpenComponentsArr,
...toRefs(pageData),
};
},
components: myComponent,
});
</script>