vue中含有iframe的页面如何避免路由切换时keep-alive不起作用

这篇博客分享了一个技术总监推荐的解决方案,针对Vue路由组件中keep-alive无法正常缓存含有iframe页面的问题。通过使用v-show切换含有iframe的组件,配合后端提供的menuType标识,以及对已打开组件的筛选,实现了绕过keep-alive限制,提高了渲染效率。同时,文章还介绍了如何监听事件以刷新特定或全部组件。
摘要由CSDN通过智能技术生成

路由组件中使用keep-alive 其他组件会正常缓存 但是含有iframe的页面无法正常缓存,这个问题困扰了我很久,也成为了项目目前的一个瓶颈。突然有一天,我们的技术总监推荐给我一篇博文,真的是让我醍醐灌顶,虽然这个keep-alive的一个问题吧,但是我们可以通过其他方式进行规避。

我们换个方式 通过v-show的方式切换含有iframe的组件

在这里插入图片描述
在这里插入图片描述

<multi-tab-store-consumer> 这个组件大家不必纠结,这个是框架自带的一个组件,忽略就可以。

  1. 后端给的路由属性中添加一个menuType标识页面中是否有iframe,如果有的话使用一个空的组件代替。
  2. 使用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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值