我正在尝试从 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/
我忽略了什么?
尽管你的
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');
};
在 javascript 中设置新创建的
src
的 iframe
不会触发 HTML 解析器,直到该元素插入到文档中。然后更新 HTML,并且将调用 HTML 解析器并按预期处理该属性。
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的答案以获得跨浏览器解决方案。
我知道这是一个老问题,但我想我会提供一个使用
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);
谢谢你提出的好问题,这让我好几次陷入困境。当使用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 有条件地延迟加载它。
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);
这样做
...
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;
}
还有另一种方法:
// 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
(函数(){
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;
})();