177

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

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

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

> 控制台.log(iframe.contentWindow);
无效的

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

我在看什么?

4

8 回答 8

264

虽然你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>

然而,iframes 有 onload 事件。这是一种将内部 html 作为 DOM (js) 访问的方法:

iframe.onload = function() {
   var div=iframe.contentWindow.document.getElementById('mydiv');
};
于 2012-05-03T14:31:44.677 回答
146

在将元素插入文档之前,在 javascript 中设置src新创建的元素不会触发 HTML 解析器。iframe然后更新 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 的答案以获得跨浏览器解决方案。

于 2012-05-02T17:53:53.743 回答
17

谢谢你的好问题,这让我好几次了。在使用 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 ”的框架访问跨域框架。

于 2015-03-01T03:58:34.210 回答
16

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

于 2014-06-24T18:43:46.763 回答
10

我知道这是一个老问题,但我想我会提供一个使用该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);

于 2020-03-27T14:29:29.650 回答
5

URL 方法仅适用于小的 HTML 片段。更可靠的方法是从 blob 生成对象 URL 并将其用作动态 iframe 的源。

const html = '<html>...</html>';
const iframe = document.createElement('iframe');
const blob = new Blob([html], {type: 'text/html'});
iframe.src = window.URL.createObjectURL(blob);
document.body.appendChild(iframe);
于 2020-06-09T22:56:39.763 回答
0

做这个

...
var el = document.getElementById('targetFrame');

var frame_win = getIframeWindow(el);

console.log(frame_win);
...

getIframeWindow在这里定义

function getIframeWindow(iframe_object) {
  var doc;

  if (iframe_object.contentWindow) {
    return iframe_object.contentWindow;
  }

  if (iframe_object.window) {
    return iframe_object.window;
  } 

  if (!doc && iframe_object.contentDocument) {
    doc = iframe_object.contentDocument;
  } 

  if (!doc && iframe_object.document) {
    doc = iframe_object.document;
  }

  if (doc && doc.defaultView) {
   return doc.defaultView;
  }

  if (doc && doc.parentWindow) {
    return doc.parentWindow;
  }

  return undefined;
}
于 2018-10-31T22:43:49.240 回答
-2

(功能(){

var frame = document.createElement('iframe');
frame.src = 'https://1zr2h9xgfxqt.statuspage.io/embed/frame';
frame.style.position = 'fixed';
frame.style.border = 'none';
frame.style.boxShadow = '0 20px 32px -8px rgba(9,20,66,0.25)';
frame.style.zIndex = '9999';
frame.style.transition = 'left 1s ease, bottom 1s ease, right 1s ease';

var mobile;
if (mobile = screen.width < 450) {
  frame.src += '?mobile=true';
  frame.style.height = '20vh';
  frame.style.width = '100vw';
  frame.style.left = '-9999px';
  frame.style.bottom = '-9999px';
  frame.style.transition = 'bottom 1s ease';
} else {
  frame.style.height = '115px';
  frame.style.width = '320px';
  frame.style.left = 'auto';
  frame.style.right = '-9999px';
  frame.style.bottom = '60px';
}

document.body.appendChild(frame);

var actions = {
  showFrame: function() {
    if (mobile) {
      frame.style.left = '0';
      frame.style.bottom = '0';
    }
    else {
      frame.style.left = 'auto';
      frame.style.right = '60px'
    }
  },
  dismissFrame: function(){
    frame.style.left = '-9999px';
  }
}

window.addEventListener('message', function(event){
  if (event.data.action && actions.hasOwnProperty(event.data.action)) {
    actions[event.data.action](event.data);
  }
}, false);

window.statusEmbedTest = actions.showFrame;

})();

于 2021-04-26T18:53:17.653 回答