0

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

然而,当我这样做时,我注意到命名空间冲突是因为用户在他们的代码中声明的变量将在 IFrame 刷新之间持久化。我通过将插入的代码包装到 IIFE 中来解决此问题,但随后注意到当用户运行一个循环然后重新加载 IFrame 两次时,将运行两个循环。

显然,IFrame 的 JavaScript 上下文没有被重置。我已经尝试过这里给出的答案,包括使用重新加载 IFrame.contentWindow.location.reload()以及更改 IFrame 源,.src = "about:blank"但这些只是重置文档的内容,而不是 IFrame JavaScript 上下文,根据这些答案,如果 IFrame 位于同一域上,则该上下文将持续存在.

这是我正在使用的实际代码(克隆存储库 -> 运行npm install-> 运行npm run dev-> 打开examples/Sandbox/index.html)。

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

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();

请参阅 JSFiddle

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

预期的行为是 IFrame 内容JavaScript 上下文应该在重新加载之间完全重置。在示例中, only2: ...应该重复打印到控制台,而不是同时打印1: ...and 2: ...。如何刷新 IFrame,使其 JavaScript 上下文不会在重新加载过程中保持不变,并且与手动重新加载页面的作用基本相同?

4

1 回答 1

1

创建 IFrame 后,您将无法编辑其源代码,以防止人们使用 IFrame 将代码注入网站以窃取信息等,或创建具有包含恶意代码的 IFrame 的假网站,以保护其他安全域。

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

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

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

container.innerHTML = "";
于 2020-01-12T10:06:35.653 回答