使用 window.postMessage实现从 iframe 关闭父页面弹框

171 阅读2分钟

工作中遇到iframe 和父级页面交互问题,及在iframe内部关闭父级页面,我用到的方法是跨域通信window.postMessage。window.postMessage 是一种安全且高效的方法,允许不同源的窗口之间进行通信。本文将详细介绍如何使用 window.postMessage 实现从 iframe 关闭父页面的弹框功能。

一、window.postMessage 介绍

window.postMessage 是一种浏览器提供的安全通信机制,允许不同源的窗口之间传递消息。它通过以下两个步骤实现通信:

  1. 发送消息:使用 window.postMessage 方法向目标窗口发送消息。
  2. 接收消息:通过监听 message 事件接收消息,并根据消息内容执行相应操作。

二、解决方法

(一)发送消息

iframe 页面中,使用 window.parent.postMessage 向父页面发送消息。postMessage 方法接受两个参数:

  1. message:要发送的消息内容,可以是字符串、对象等。
  2. targetOrigin:目标窗口的源,用于指定消息可以发送到哪些源。为了安全起见,应尽可能指定一个具体的源,而不是使用通配符 *
    window.parent.postMessage('close-modal', 'http://origin.com');

(二)接收消息

在父页面中,监听 message 事件以接收来自 iframe 的消息。通过 event 对象可以获取消息内容和发送消息的窗口的源。为了安全起见,应验证 event.origin 是否为预期的源。

// 在父页面中
window.addEventListener('message', function(event) {
    // 验证消息的来源
    if (event.origin !== 'http://iframe-source-domain.com') {
        console.warn('Invalid message origin:', event.origin);
        return;
    }
    // 处理接收到的消息
    if (event.data === 'close-modal') {
        closeModal();
    }
});

closeModal() {
    // 关闭弹框
    document.getElementById('modal').style.display = 'none';
}

三、完整示例

(1)父页面代码

<body>
    <div id="app">
        <button onclick="openModal()">Open</button>
        <div id="modal" class="ant-modal-root" style="display: none;">
            <div class="ant-modal-mask"></div>
            <div class="ant-modal-wrap">
                <div class="ant-modal">
                    <div class="ant-modal-content">
                        <div class="ant-modal-body">
                            <iframe src="./iframe.html" style="width: 100%; height: 300px;"></iframe>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <script>
        function openModal() {
            document.getElementById('modal').style.display = 'block';
        }

        function closeModal() {
            document.getElementById('modal').style.display = 'none';
        }

        // 监听来自 iframe 的消息
        window.addEventListener('message', function (event) {
            // 验证消息来源(这里假设父子页面同源,使用 '*' 作为示例)
            if (event.origin !== 'http://localhost') {
                console.warn('Invalid message origin:', event.origin);
                return;
            }
            if (event.data === 'close-modal') {
                closeModal();
            }
        });
    </script>
</body>

(2)iframe 页面代码

<body>
    <button onclick="closeParentModal()">Close</button>
    <script>
        function closeParentModal() {
            // 向父页面发送关闭弹框的消息
            window.parent.postMessage('close-modal', '*');
        }
    </script>
</body>

四、注:

  1. 验证 event.origin:为了防止恶意网站发送消息,务必验证 event.origin 是否为预期的源。
  2. 使用具体源:在调用 postMessage 时,尽量使用具体的源而不是通配符 *,以提高安全性。
  3. 处理消息内容:对接收到的消息内容进行验证和处理,确保其符合预期格式和内容。
  4. window.parent.postMessage 可以发送复杂数据:比如对象或数组。该方法支持 JSON 可序列化的数据,因此您可以将 JavaScript 对象和数组作为消息内容传递。只需确保数据可以在 iframe 和父窗口之间安全地序列化和反序列化。