iframe 详解-在vue中使用iframe/iframe在vue中使用
一、什么是iframe?
1. 使用 iframe + postMessage 实现跨域通信
MDN: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage
在实际项目开发中可能会碰到在 aa.com 页面中嵌套 bb.com 页面,这时第一反应是使用 iframe,但是产品又提出在 aa.com 中操作,bb.com 中进行显示,或者相反。
postMessage语法:
otherWindow.postMessage(message, targetOrigin, [transfer]); otherWindow:其他窗口的一个引用(在这里我使用了iframe的contentWindow属性) message:将要发送到其他window的数据 targetOrigin:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项
不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,
必须保证它的值与这条包含密码的信息的预期接受者的origin属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。
不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。 transfer:可选参数
二、遇到的问题
1. postMessage发送消息跨域问题
// 不限制域名就用*,否则就是具体域名,这样可以解决跨域问题
iframe.postMessage(dict, '*')
2. postMessage传递数据的格式
data: {// 最外面这个是postMeaage自带的,下面才是自己定义的数据格式,也可以不要内层的data:
data: {
responseCode: '000000'
body: {
id: ""
name: "模板1"
}
}
type: "TYPE"
}
三、实例代码如下:下面的是iframe实用的例子,应用的是postMessage发送的消息,本例是父组件往子组件传递数据
注意:如果使用postMessage发送消息时,如果不使用按钮触发的话,有可能发送失败,所以下面例子针对此情景做了发送消息失败的处理方案
<template>
<div class="main-info">
<iframe
ref="iframe"
id="iframe"
frameborder="0"
:src="iframeSrc"
style="min-height: 800px;width: 100%"
>
</iframe>
</div>
</template>
// 定义数据
data () {
return {
iframeSrc: '',
iframe: '',
isReceiveMsg: false, // 是否收到消息,收到消息停止计时器,不再发送postMessage消息
actionNum: 5, // 最多执行5次
timer: null,// 定时器
}
},
created() {
this.iframeSrc = `http://www.baidu.com`
// 监听收到消息
window.addEventListener('message', this.handleMessageEvent)
},
mounted () {
const self = this
this.$nextTick(() => {
const iframe = document.getElementById('iframe')
if (iframe.attachEvent) { // 适配IE
iframe.attachEvent('onload', function () {
self.clickIframe()
setTimeout(() => {
self.handlePostMessageFail()
}, 1000)
})
} else {
iframe.onload = function () {
// 坑一,postMessage发送通知时,可能对方的页面还没有加载完成导致发送失败
self.clickIframe()
setTimeout(() => {
self.handlePostMessageFail()
}, 1000) } } })
}
},
methods: {
handleMessageEvent(event) {
if (event.data && event.data.data) {
const data = event.data.data
const body = data.body || ''
if (parseInt(data.responseCode) === 0) {
// 成功返回
setTimeout(() => {
this.$router.push({ name: this.backPath })
}, 500)
} else if (parseInt(data.responseCode) === 2) {
// 收到消息
console.log('-------已收到消息', data)
this.isReceiveMsg = true
}
}
},
clickIframe() {
const iframe =
document.getElementById('iframe') &&
document.getElementById('iframe').contentWindow
if (!iframe) return
const list = []
list.push(this.processData)
const dict = {
processList: list
}
// 不限制域名就用*,否则就是具体域名
iframe.postMessage(dict, '*')
},
// 其中clickIframe里是处理iframe的src的
// 处理失败机制
// postMessage消息发送失败机制,上面定义执行5次,第隔1.5秒,之前设置3次,间隔一秒,还是有失败的,所以这里采用这个
handlePostMessageFail () {
this.timer = setInterval(() => {
if (!this.isReceiveMsg) {
if (this.actionNum <= 0) {
clearInterval(this.timer)
this.timer = null
this.isReceiveMsg = true
return
}
this.clickIframe()
this.actionNum--
} else {
clearInterval(this.timer)
this.timer = null
this.isReceiveMsg = true
}
}, 1500)
},
// 记得离开页面时,要消毁掉
destroyed() {
window.removeEventListener('message', this.handleMessageEvent)
}
将来的自己,会感谢现在不放弃的自己!

浙公网安备 33010602011771号