如何创建 iframe 元素并动态设置其 HTML?

问题描述 投票:0回答:9

我正在尝试从 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/

我忽略了什么?

javascript iframe
9个回答
291
投票

尽管你的

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 事件。这是一种以 DOM (js) 形式访问内部 html 的方法:

iframe.onload = function() {
   var div=iframe.contentWindow.document.getElementById('mydiv');
};

152
投票

在 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的答案以获得跨浏览器解决方案。


29
投票

我知道这是一个老问题,但我想我会提供一个使用

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


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”的框架访问跨源框架。


17
投票

还有另一种方法可以创建内容为 HTML 字符串的 iframe:srcdoc 属性。 较旧的浏览器不支持此功能(其中主要是:Internet Explorer,可能还有 Safari?),但有一个用于此行为的 polyfill,您可以将其放入 IE 的条件注释中,或使用类似 has 的内容。 js 有条件地延迟加载它。


10
投票

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

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;
}

0
投票

还有另一种方法:

  // 1. Create elements with regular strings
  const myIframeContent = `<h1>Sup</h1>`;
  
  // 2. Set the `srcdoc` aka HTML of the iframe
  const myNewIframe = `<iframe id="myIframe" srcdoc="${myIframeContent}"></iframe>`;
  
  // 3. Magically turn those strings in to HTML by appending the string to the document.body
  document.body.insertAdjacentHTML('beforeend', myNewIframe);
  
  // 4. Look at all the cools things you have now!
  console.log('[myIframe.contentWindow]', myIframe.contentWindow);

文档:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe


-3
投票

(函数(){

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;

})();

© www.soinside.com 2019 - 2024. All rights reserved.