Reset/Reload IFrame JavaScript 上下文

Reset/Reload IFrame JavaScript context

我正在创建一个交互式代码编辑器,它由一个文本框和一个 <iframe> 元素组成。每当用户在文本框中键入代码时,都会写入 IFrame 的内容,并且 IFrame 内的 <script> 标记会填充代码文本框的内容,从而导致用户键入的代码为 运行 在 IFrame 中。每次用户输入时,IFrame 应该是 reset/reloaded 并且文档会再次写入 IFrame 脚本标记中文本框的新内容,本质上是在他们输入时自动 运行ning 任何代码输入它。

但是,在执行此操作时,我注意到命名空间冲突的发生是因为用户在其代码中声明的变量将在 IFrame 刷新之间保留。我通过将插入的代码包装到 IIFE 中来修复此问题,但随后注意到当用户 运行 循环然后重新加载 IFrame 两次时,two 循环将是 运行宁.

显然,IFrame 的 JavaScript 上下文没有被重置。我已经尝试过如果 IFrame 在同一域中,答案 given here including reloading the IFrame using .contentWindow.location.reload() as well as changing the IFrame source with .src = "about:blank" but these just reset the content of the document, not the IFrame JavaScript context which according to these answers 会被保留。

Here is the actual code that I am working with(克隆存储库 -> 运行 npm install -> 运行 npm run dev -> 打开 examples/Sandbox/index.html)。

这是该问题的最小可重现示例(依赖于 ID 为 frame 的 IFrame 元素上的存在):

const frame = document.getElementById("frame");
let i = 1;

function updateFrame() {
    frame.contentWindow.location.reload();

    frame.contentDocument.open();

    frame.contentDocument.write(`
        <html>
            <body>
                <script>
                    (function() {
                        let a = 0;

                        function print() {
                            console.log(${i++} + ": " + a++);

                            requestAnimationFrame(print);
                        }

                        print();
                    })();
                </script>
            </body>
        </html>
    `);

    frame.contentDocument.close();
}

updateFrame();
updateFrame();

See on JSFiddle.

注意 updateFrame() 被调用了两次,这应该会重新加载 IFrame 的内容,只留下第二个循环 运行ning,但是两个 print() 循环同时打印到控制台,表明上下文在整个重新加载过程中保持不变。

预期的行为是 IFrame 内容 JavaScript 上下文应在重新加载之间完全重置。在示例中,只有 2: ... 应该重复打印到控制台,而不是 1: ...2: ...。如何刷新 IFrame,使其 JavaScript 上下文 而不是 在整个重新加载过程中持续存在,并且本质上与手动重新加载页面的行为相同?

创建 IFrame 后,您无法编辑其源代码,以防止有人使用 IFrame 将代码注入网站以窃取信息等目的,或创建假冒网站,这些假冒网站的 IFrame 中包含恶意代码,以其他方式保护域。

您必须通过 AJAX 将更新从编辑器呈现到 PHP 服务器或 node.js 等后端,或者完全删除 IFrame 元素并创建一个全新的通过

var if = document.createElement("IFRAME");
if.src = /* your code */
var container = document.getElementById("container");

然后每次需要更新时使用类似的系统删除该项目。

container.innerHTML = "";