我最近在开发一个代码共享平台,需要实现代码编辑器与运行环境之间的隔离。左侧是代码编辑器,右侧是运行结果展示区,包括控制台和渲染画布。为了隔离 JavaScript 代码,我选择了 iframe 作为解决方案。iframe 的 srcdoc 属性可以注入要执行的代码,这样就形成了一个独立的运行环境。为了方便查看 iframe 中控制台的输出,我需要实现父窗口与子窗口之间的通信。这里就涉及到 iframe 的基本通信机制。我们先来看一下基本的 HTML 结构。父窗口的 HTML 文件如下:<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>父窗口</title></head><body><p>父窗口</p><iframe src="./sub.html"></iframe><button onclick="sendMessage()>发送一条消息给子窗口</button><p id="response"></p></body></html>子窗口的 HTML 文件如下:<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>子窗口</title></head><body><p>子窗口</p><button onclick="sendMessage()>发送一条消息给父窗口</button><p id="response"></p></body></html>通过这些简单的 HTML 结构,我们可以看到它们的关系是嵌套的。现在,我们来实现父窗口的 sendMessage 方法:let sub = window.frames[0]function sendMessage() { sub.postMessage({ msg: "来自父窗口的一条消息" })}这里我们通过 window.frames 获取到子窗口的引用,然后通过 postMessage 方法发送消息。在子窗口中,我们需要监听 message 事件来接收消息:const responseEl = document.getElementById("response")window.addEventListener("message", function (e) {responseEl.innerHTML += `收到一条消息:${e.data.msg}<br>`})这样,我们就实现了 iframe 之间的双向通信。需要注意的是,postMessage 方法只支持 JSON 支持的类型。如果我们需要传递函数,可以通过将函数转换为字符串来实现。但是,如果函数中引用了外部变量,接收端就无法访问这些变量。因此,建议使用纯函数来避免这些问题。最后,我们可以通过劫持 console 对象的方法来实现在父窗口中同步子窗口的控制台输出。var fns = new Map()for(let key in console) {fns.set(key, console[key])console[key] = (...args) = {funcToString(args)window.parent.postMessage({ type: 'console.' + key, args }, "*")return fns.get(key)(...args)}}通过这段代码,我们可以将子窗口的 console 输出同步到父窗口。以上就是关于 iframe 实现多窗口通信的详细内容。