我正在创建一个由文本框和<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();
请注意,它updateFrame()
被调用了两次,它应该重新加载 IFrame 的内容,只留下第二个循环运行,但是两个print()
循环同时打印到控制台,表明上下文在整个重新加载过程中保持不变。
预期的行为是 IFrame 内容和JavaScript 上下文应该在重新加载之间完全重置。在示例中, only2: ...
应该重复打印到控制台,而不是同时打印1: ...
and 2: ...
。如何刷新 IFrame,使其 JavaScript 上下文不会在重新加载过程中保持不变,并且与手动重新加载页面的作用基本相同?