动态创建具有给定 HTML 的 iframe

IT技术 javascript iframe
2021-02-09 00:53:49

我正在尝试从 JavaScript 创建一个 iframe 并用任意 HTML 填充它,如下所示:

var html = '<body>Foo</body>';
var iframe = document.createElement('iframe');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);

我希望iframe然后包含一个有效的窗口和文档。然而,情况并非如此:

> console.log(iframe.contentWindow);
空值

自己试试:http : //jsfiddle.net/TrevorBurnham/9k9Pe/

我在看什么?

6个回答

虽然你src = encodeURI应该工作,但我会采取不同的方式:

var iframe = document.createElement('iframe');
var html = '<body>Foo</body>';
document.body.appendChild(iframe);
iframe.contentWindow.document.open();
iframe.contentWindow.document.write(html);
iframe.contentWindow.document.close();

由于这没有 x 域限制并且完全通过iframe句柄完成,您可以稍后访问和操作框架的内容。您需要确保的是,内容已经呈现,这将(取决于浏览器类型)在 .write 命令发出期间/之后开始 -close()调用时不一定完成

100% 兼容的回调方法可能是这种方法:

<html><body onload="parent.myCallbackFunc(this.window)"></body></html>

但是,iframe 具有 onload 事件。这是一种将内部 html 访问为 DOM (js) 的方法:

iframe.onload = function() {
   var div=iframe.contentWindow.document.getElementById('mydiv');
};
有趣的document.body.appendChild(iframe)是,这是工作所必需的。
2021-03-29 00:53:49
这适用于 Internet Explorer!这很方便,因为数据 URI 不能在任何版本的 IE 中用作 iframe 源。 caniuse.com/#feat=datauri
2021-03-31 00:53:49
@mschr 此方法是否支持完整的 HTML 页面代码,其中还加载了包含和样式表?参见stackoverflow.com/questions/19871886
2021-04-02 00:53:49
有趣的; 我以前从未见过这种技术。我知道 URI 编码/解码会增加性能影响,但我也看到它被描述为不支持srcdocproperty 的环境中的唯一替代方案这种document.write方法有什么缺点吗?
2021-04-04 00:53:49
基本上,是的,我相信它应该在那里发表评论。该技术基本上打开一个输入文本流,您可以通过 document.write 写入该流。反过来,正常加载网页通过 websocket-stream 检索它。
2021-04-06 00:53:49

在将元素插入到文档中之前,在 javascript 中设置src新创建的iframe不会触发 HTML 解析器。然后更新 HTML,将调用 HTML 解析器并按预期处理属性。

http://jsfiddle.net/9k9Pe/2/

var iframe = document.createElement('iframe');
var html = '<body>Foo</body>';
iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);
document.body.appendChild(iframe);
console.log('iframe.contentWindow =', iframe.contentWindow);

此外,此回答您的问题很重要,请注意此方法与某些浏览器存在兼容性问题,请参阅@mschr 的答案以获取跨浏览器解决方案。

请注意,encodeURI(...)它不会对所有字符进行编码,因此如果您的 HTML 包含特殊字符,例如#,则会中断。encodeURIComponent(...)对这些字符进行编码。看到这个答案
2021-03-13 00:53:49
甚至在 IE10 中都不起作用。@mschr 的答案肯定适用于 IE7+,甚至可能是旧版本。
2021-03-20 00:53:49
他的问题是“我在俯瞰什么?” 这就是 iframe 没有附加到文档的事实。我从来没有声称它是跨浏览器的,而且在我回答有人真的抱怨之后才一年多。不,它不是跨浏览器。但老实说,如果您想要代码质量,那么可能有比首先使用 iframe 更简洁的解决方案:)
2021-04-02 00:53:49

感谢您提出的好问题,这让我不知所措。在使用 dataURI HTML 源时,我发现我必须定义一个完整的 HTML 文档。

请参阅下面的修改示例。

var html = '<html><head></head><body>Foo</body></html>';
var iframe = document.createElement('iframe');
iframe.src = 'data:text/html;charset=utf-8,' + encodeURI(html);

注意用<html>标签和iframe.src字符串包装的 html 内容

需要将 iframe 元素添加到要解析的 DOM 树中。

document.body.appendChild(iframe);

iframe.contentDocument除非您disable-web-security在浏览器上否则您将无法检查你会收到一条消息

DOMException: 无法从 'HTMLIFrameElement' 读取 'contentDocument' 属性:阻止了一个具有源“ http://localhost:7357 ”的框架访问跨源框架。

创建内容为 HTML 字符串的 iframe 的替代方法是:srcdoc 属性这在较旧的浏览器中不受支持(其中主要是:Internet Explorer,可能还有 Safari?),但是这种行为有一个polyfill,你可以在 IE 中添加条件注释,或者使用诸如 has.js 之类的东西来有条件地懒惰加载它。

对此的支持现在非常主流(IE 除外)。这绝对比直接访问 contentDocument 更可取 - 特别是因为如果与沙箱属性结合使用,您将无法访问 contentDocument。
2021-03-15 00:53:49

我知道这是一个老问题,但我想我会提供一个使用该srcdoc属性的示例,因为它现在得到广泛支持,并且经常查看这个问题。

使用该srcdoc属性,您可以提供要嵌入的内联 HTML。src如果支持,它会覆盖该属性。src如果不支持,浏览器将回退到该属性。

我还建议使用该sandbox属性对框架中的内容应用额外的限制。如果 HTML 不是您自己的,这一点尤其重要。

const iframe = document.createElement('iframe');
const html = '<body>Foo</body>';
iframe.srcdoc = html;
iframe.sandbox = '';
document.body.appendChild(iframe);

如果您需要支持较旧的浏览器,您可以srcdoc从其他答案中检查是否支持并回退到其他方法之一。

function setIframeHTML(iframe, html) {
  if (typeof iframe.srcdoc !== 'undefined') {
    iframe.srcdoc = html;
  } else {
    iframe.sandbox = 'allow-same-origin';
    iframe.contentWindow.document.open();
    iframe.contentWindow.document.write(html);
    iframe.contentWindow.document.close();
  }
}

var iframe = document.createElement('iframe');
iframe.sandbox = '';
var html = '<body>Foo</body>';

document.body.appendChild(iframe);
setIframeHTML(iframe, html);

这种用法可以使用 postMessage 向 iframe 内的 JavaScript 发送一条消息,描述需要发生哪些更改,然后 iframe 可以使用自己的代码更新自身。有点棘手,但我认为这是唯一的方法。
2021-03-15 00:53:49
但是如果不需要创建新元素呢?如果 iframe 已经存在并且数据只是要更新?
2021-04-02 00:53:49