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语法:
1 2 3 4 5 6 | otherWindow.postMessage(message, targetOrigin, [transfer]); otherWindow:其他窗口的一个引用(在这里我使用了iframe的contentWindow属性) message:将要发送到其他window的数据 targetOrigin:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串 "*" (表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项<br>不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,<br>必须保证它的值与这条包含密码的信息的预期接受者的origin属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。<br>不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。 transfer:可选参数 |
二、遇到的问题
1. postMessage发送消息跨域问题
1 2 | // 不限制域名就用*,否则就是具体域名,这样可以解决跨域问题 iframe.postMessage(dict, '*' ) |
2. postMessage传递数据的格式
1 2 3 4 5 6 7 8 9 10 | data: { // 最外面这个是postMeaage自带的,下面才是自己定义的数据格式,也可以不要内层的data: data: { responseCode: '000000' body: { id: "" name: "模板1" } } type: "TYPE" } |
三、实例代码如下:下面的是iframe实用的例子,应用的是postMessage发送的消息,本例是父组件往子组件传递数据
注意:如果使用postMessage发送消息时,如果不使用按钮触发的话,有可能发送失败,所以下面例子针对此情景做了发送消息失败的处理方案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | <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) } |
将来的自己,会感谢现在不放弃的自己!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· 单线程的Redis速度为什么快?
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码