vue3.0 用iframe嵌入react项目

公司项目要求把之前react项目嵌入到vue3.0项目中,想了好久iframe是一种解决方案

需求:
在vue3.0项目中菜单点击时,打开react项目中的一个页面,react页面内部跳转的时候通知vue3.0,打开一个tab(互相通信)

需要注意:
keepalive不缓存iframe 需要找另一个解决方案,把iframe写在route之外

app.vue

<el-main id="app">
        <router-view
          ref="pageRef"
          @hook:mounted="onMounted"
          v-slot="{ Component }"
        >
          <keep-alive :include="keepAliveList" :max="10">
            <component :is="Component"  v-if="!route.meta.href"/>
          </keep-alive>
        </router-view>
      </el-main>
        <div 
          class="class-for-iframe" 
          v-for ="item in showIframeTabArr" 
          :key= "item.name" 
          v-show="item.href.indexOf(route.meta.href)>-1 && item.name === route.name"
          >
          <Iframe :key="item.name" :href="item.href" :id="item.name"></Iframe>
        </div>
    </el-container>

在vue项目中全局监听子组件传过来的消息(APP.VUE文件)

 setup () {
    window.addEventListener('message', receiveMessage, false);
    function receiveMessage (event:any)  {
      console.log("父組件接收的消息",event);
      const showIframeTabArr: ComputedRef<any[]> = computed(() => {
        return store.state.tabs.showIframeTabArr;
      })
      const tabs: ComputedRef<any[]> = computed(() => {
        return store.state.tabs.tabs;
      })
      // const { activeTab, tabList, dispatch } = this.props;
      if (event !== undefined && event.data) {
        const {  domainName,isCloseTab } = event.data;
        // iframe里面 跳转新的页面,通知父组件打开,带上参数
        if (domainName) {
          const obj = {
            ...event.data,
          };
          obj.key = event.data.route.split('?')[0].split('/')[
            event.data.route.split('?')[0].split('/').length - 1
          ]; 
        
          const path = obj.route;
          const params = path.split('?'); 
          const iframeUrl = "https://prituat.phfund.com.cn";
          const href = params.length>1?`${iframeUrl}${path}&iframe=1` : `${iframeUrl}${path}?iframe=1`;
          const selectMenuItem = 
            findMenuItem(menuList.value, path) 
            || 
            {title:obj.title,path:`/${APP_NAME}${path.split('?')[0]}`,name:obj.key,href};
          const tabItem = { label: selectMenuItem.title, path: selectMenuItem.path,name:obj.key,href };
          if( tabItem.name === 'offsiteSystem' ||
              tabItem.name === 'dashboard' ||
              tabItem.name === 'newCalendar' ||
              tabItem.name === 'etfwebscoket'){
              GetChildIframe({...tabItem, orgin: { Interval: '2' }})
          }else{
              const res = tabs.value.filter((t:any) => 
                t.name === 'offsiteSystem' 
              );
              res.map((a:any)=>{
                GetChildIframe({...a, orgin: { Interval: '1' }})
              })
          }
          // 按react项目里面的 用component 组件名判断是否重复
          if (tabs.value.some(tab => tab.name === selectMenuItem.name)) {
            store.dispatch('updateTab', {
              index: tabs.value.findIndex(tab => tab.name === selectMenuItem.name),
              tab: tabItem
            })
            store.dispatch('updateShowIframeTabArr', {
              index: showIframeTabArr.value.findIndex(tab => tab.name === selectMenuItem.name),
              tab: tabItem
            })
            // console.log("需要更新",tabs);
            router.push({path:`/${APP_NAME}${path.split('?')[0]}`,query:{href}});
          } else {
            // console.log("这是新增");
            store.dispatch('createShowIframeTabArr', tabItem)
            store.dispatch('createTab', tabItem)
            router.push({path:`/${APP_NAME}${path.split('?')[0]}`,query:{href}});
          }
        }

        if (isCloseTab) {
          const cur = tabs.value.findIndex(item=>  item.path.indexOf(route.path)>-1);
          const curiframe = showIframeTabArr.value.findIndex(item=>  item.path.indexOf(route.path)>-1);
          close(route.path,cur,false);
          close(route.path,curiframe,true);
        }
      }
    }

 }

iframe.vue

<template>
    <iframe 
      :src="href" 
      width="100%" height="100%" frameborder="0" scrolling="auto">
    </iframe>
</template>

vue中菜单点击跳转页面,打开tab栏直接按照官方文档来即可
需要注意的是:
要两个数组(store)用来存放,一个存“tabs”放vue项目中自己的tab
另一个“showIframeTabArr”用来存放iframe相关的tab

因为iframe中可能存在定时器,跳转到别的页面时需要关闭定时器,只需要调用GetChildIframe给子组件发消息,写在了通用工具里,当然react项目中需要接收到该参数并停止定时器

export function GetChildIframe (data:any) {
  const { orgin, path } = data;
  const Id = path.split('?')[0].split('/')[
    path.split('?')[0].split('/').length - 1
  ];
  // const { currentUser } = window.g_app._store.getState().user;, currentUser
  const parent = { ...orgin, noAjaxUser: true };
  setTimeout(() => {
    const iframes: any = document.getElementById(`${Id}`);
    // console.log(iframes);
    if(iframes)
      iframes.contentWindow.postMessage(parent, '*');
  }, 1000);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值