需求
一个vue项目中通过iframe嵌套另外一个vue项目,如何让这两个项目之间进行通信
分析
在Vue项目中通过iframe嵌套另外一个Vue项目时,可以通过postMessage方法实现这两个项目之间的通信。postMessage是HTML5新增加的API,它允许在不同的window或iframe之间发送消息。
页面嵌入
<template>
<div class="container1" v-loading="loading">
<iframe id="modle_iframe" :key="ikey" ref="Iframe" :src="url" width="100%" height="100%" frameborder="0" />
</div>
</template>
<script lang="ts" setup>
import { onMounted, ref, watchEffect } from 'vue';
const ikey = new Date().getTime() // 使用时间戳
const Iframe = ref()
const loading = ref(false)
function iframeLoad() {
loading.value = true
const iframe = Iframe.value
// 兼容处理
if (iframe.attachEvent) {
// IE
iframe.attachEvent('onload', () => {
loading.value = false
})
} else {
// 非IE
iframe.onload = () => {
loading.value = false
}
}
}
const url = ref()
const fetchData = () => {
if (!url.value) {
// ikey.value = new Date().getTime() // 使用时间戳
url.value = 'http://localhost:9001/#/home?projectId=1595297518537670657&structId=1592065978097729537&token=52212e27-9f6a-47f6-b4aa-a7d21b9d636d'
}
iframeLoad()
};
onMounted(() => {
fetchData();
});
</script>
<script lang="ts">
export default {
name: 'Model',
};
</script>
<style scoped lang="less">
.container1 {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
}
#modle_iframe {
width: 100%;
height: 100%;
}
</style>
父传子
- A项目中父组件中调用B项目并发送 msg
<template>
<iframe id="modle_iframe" ref="Iframe" :src="url" frameborder="0" />
</template>
<script>
export default {
name: 'Index',
data () {
return {
viewer: null,
url: '',
projectId: this.$store.state.project.projectId,
structId: this.$store.state.struct.structId,
token: getToken()
}
},
mounted () {
const iframe = document.getElementById('modle_iframe')
const port = process.env.NODE_ENV === 'development' ? 9002 : 41003
const baseUrl = `${window.location.protocol}//${window.location.hostname}:${port}/#/home`
this.url = `${baseUrl}?projectId=${this.projectId}&structId=${this.structId}&token=${this.token}&sign=9`
const obj = {
sign: 'safeDaba',
value: '9'
}
const msg = JSON.stringify(obj)
iframe.contentWindow.postMessage(msg, '*')
// this.$nextTick(() => {
// this.init()
// })
},
methods: {
}
}
</script>
<style scoped>
#modle_iframe {
width: 100%;
height: 600px;
}
</style>
- B项目中子组件中接收B项目发送的 msg
window.addEventListener('message', function (e) {
e.stopPropagation();
//防止异常
try {
let data = JSON.parse(e.data); //转化为json
if (data.sign === 'waterAndRain') {
if (data.value === '1') {
}
} else {
}
} catch (err) {
}
});
如果上述代码看不太明白,那么
下面是一个示例代码,演示了如何在父窗口和子窗口之间使用postMessage方法进行通信:
在父窗口中:
// 获取iframe元素
const iframe = document.querySelector('#myIframe')
// 监听message事件
window.addEventListener('message', (event) => {
// 判断消息来源是否为iframe的地址
if (event.source === iframe.contentWindow) {
// 处理接收到的消息
console.log('收到来自子窗口的消息:', event.data)
}
})
// 发送消息给iframe
iframe.contentWindow.postMessage('Hello from parent', '*')
在子窗口中:
// 监听message事件
window.addEventListener('message', (event) => {
// 判断消息来源是否为父窗口的地址
if (event.source === window.parent) {
// 处理接收到的消息
console.log('收到来自父窗口的消息:', event.data)
// 发送消息给父窗口
window.parent.postMessage('Hello from child', '*')
}
})
在上述代码中,我们首先获取了用于嵌套另一个Vue项目的iframe元素。然后,在父窗口中监听了message事件,当接收到来自iframe的消息时,就会将消息打印输出到控制台中。
接着,在父窗口中使用postMessage方法向iframe发送了一条消息。
在子窗口中,我们也监听了message事件,并判断消息来源是否为父窗口的地址。当接收到来自父窗口的消息时,就会将消息打印输出到控制台中,并使用postMessage方法向父窗口发送了一条消息。
需要注意的是,当使用postMessage方法发送消息时,第二个参数指定的是消息的目标窗口的origin,这里我们使用通配符*表示允许发送消息到任何域名,但在实际应用中建议设置具体的域名。
子传父
首先,在被调用者子组件中,使用postMessage方法将消息传递给父窗口:
- 子页面
// 在被调用者子组件中
// 向父窗口发送消息
window.parent.postMessage('Hello from child', '*')
然后,在调用者父组件中,通过监听message事件接收子组件传递的消息:
mounted() {
window.addEventListener('message', this.handleMessage)
},
methods: {
handleMessage(event) {
// 处理接收到的消息
console.log('收到来自子组件的消息:', event.data)
},
}
或
// 在调用者父组件中
// 监听message事件
window.addEventListener('message', (event) => {
// 判断消息来源是否为被调用者子组件的地址
if (event.source === document.querySelector('iframe').contentWindow) {
// 处理接收到的消息
console.log('收到来自子组件的消息:', event.data)
}
})
在上述代码中,被调用者子组件通过window.parent.postMessage方法将消息发送给父窗口。注意,这里的window.parent表示父窗口的全局对象。
在调用者父组件中,我们使用window.addEventListener方法监听message事件,并通过判断消息来源是否为被调用者子组件的地址来确定是否处理该消息。
通过这种方式,被调用者子组件可以将消息传递给调用者父组件,实现跨域通信。
需要注意的是,由于涉及到跨域通信,需要确保两个项目的域名不同,否则会受到浏览器的同源策略限制。同时,也需要确保被嵌套的项目正确设置了允许跨域访问的响应头。