处理iframe中的通信

在现代web开发中,经常会遇到需要在不同iframe之间进行通信的情况。尤其是当涉及到老旧的遗留应用程序时,这些应用程序可能还依赖于过时的技术,如Internet Explorer 6。在这种情况下,iframe的使用非常普遍,不仅仅是为了嵌入其他站点的内容,还用于跨域Ajax、覆盖选择框的覆盖层,或者模拟桌面窗口布局等。本文将探讨如何在这些老旧的应用程序中,通过JavaScript的postMessage方法,实现iframe之间的安全通信。

直接访问(不推荐的方式)

在iframe之间进行交互的一种方法是直接访问嵌套或父iframe的DOM元素(如果同源策略允许的话)。例如,可以通过以下代码修改嵌套iframe中的元素状态:

document.getElementById('someIframe').contentWindow.document.getElementById('someInput').value = 'test';

而访问父iframe中的元素可以通过以下代码实现:

window.parent.document.getElementById('someInput').value = 'test';

这种方法的问题在于它紧密地耦合了iframe,这很不幸,因为iframe的使用初衷是为了提供某种封装。直接DOM访问的另一个缺点是,在深度嵌套的情况下会变得非常复杂:

window.parent.parent.parent.document...

消息传递(推荐的方式)

为了实现iframe之间的安全跨域通信,浏览器引入了postMessage方法。本文假设应用程序中的iframe可以运行在Internet Explorer 11中,这是微软在2013年发布的最后一个版本。尽管需要支持Internet Explorer,但至少是它的最新版本。

通过postMessage方法,可以很容易地创建一个小型消息总线,以便在一个iframe中触发的事件可以在另一个iframe中处理,前提是目标iframe选择采取行动。这种方法减少了iframe之间的耦合,因为一个框架不需要知道另一个框架的任何细节。

以下是一个示例函数,可以将消息发送到所有直接嵌套的iframe:

const sendMessage = function(type, value) { console.log('[iframe0] Sending message down, type: ' + type + ', value: ' + value); var iframes = document.getElementsByTagName('iframe'); for (var i = 0; i < iframes.length; i++) { iframes[i].contentWindow.postMessage({ direction: 'DOWN', type: type, value: value }, '*'); } };

在上面的代码中,使用document.getElementsByTagName找到了iframe,然后通过contentWindow.postMessage调用向它们发送消息。postMessage方法的第一个参数是想要传递的消息(数据)。浏览器会负责其序列化,需要决定需要传递什么。选择传递一个具有3个属性的对象:第一个指定消息应该朝哪个方向发送(UP或DOWN),第二个状态消息类型(例如UPDATE_USER),最后一个包含消息的有效载荷。在示例应用程序中,它将是用户输入的文本,这将影响嵌套iframe中的元素。传递给contentWindow方法的'*'值决定了浏览器如何分派事件。星号意味着没有限制 - 对于代码示例来说是可以的,但在现实世界中,应该考虑提供一个URI作为参数值,以便浏览器能够根据方案、主机名和端口号限制事件。

以下是如何在iframe中接收消息的示例:

window.addEventListener('message', function(e) { // Do something with e.data... });

在上面的代码中,通过监听window对象上的message事件来捕获消息。传递的消息可以在事件的data字段中找到,因此对e.data.type进行检查,以查看代码是否应该处理消息或只是将其传递。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485