创建新的 iframe 并同步加载内容

Posted

技术标签:

【中文标题】创建新的 iframe 并同步加载内容【英文标题】:Create new iframe and load content synchronously 【发布时间】:2019-10-05 07:55:41 【问题描述】:

我们的目标是动态创建一个 iframe,并将一个 SVG 元素同步附加到其文档正文中。

我们正试图让它在 Firefox 中工作。

我们的研究表明,Firefox 在将 iframe 附加到 html 后会使用新文档重置 iframe。这会触发一个加载事件,只有在此事件之后,您才能成功附加内容。在加载事件之前附加的任何内容都会被丢弃。

不理想的解决方法是等待加载事件,然后将 SVG 元素附加到 iframe。

是否可以避免异步行为?我们希望在创建 iframe 后同步附加 SVG 元素。

Codepen:https://codepen.io/anon/pen/yWXjgM

var newElem = $(document.createElement("div"));
newElem.html("hi there");
var iframe = $(document.createElement("iframe"));
iframe.contents().find("body").append(newElem);
$("#box").append(iframe);
$("#box").append(newElem);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="box"></div>

【问题讨论】:

你真的在 Chrome 中测试过这段代码吗?它在那里也不起作用。 OK 更新了问题以删除对 Chrome 的引用。只是想看到它在 Firefox 中运行。这是我们代码库的简化版本,因此只是缩小了问题的范围以消除歧义。感谢您的帮助。 iframe 指向哪里?它与父页面在同一个域上吗?是否在同一个子域上? 与父页面相同的域。这只是一种将父元素沙箱化的方法。 【参考方案1】:

tl:dr 不管做了什么,正在加载的 iframe 的异步性质似乎是无法避免的,但是有一种同步的方式来添加内容通过srcdoc 动态到iframe,它“覆盖”了默认的iframe src 属性。

它也会出现可能使用createHTMLDocument 的解决方案,但我还没有成功。

srcdoc 的解决方案

说明

假设您的动态 iframe 不通过 src 属性加载内容

根据HTML iframe specifications

当 iframe 元素插入到具有浏览上下文的文档中时,用户代理必须创建嵌套的浏览上下文,然后“第一次”处理 iframe 属性。

需要注意的是“第一次处理 iframe 属性”。 没有提及这个过程是同步的还是异步的,它取决于每个浏览器的实现。

如前所述,Chrome 和 Firefox 已将此过程理解为异步的,这确实有意义,因为 iframe 的目标是从其 src 属性加载内容并调用 onload 回调。

如果没有可用的src 属性,它将设置为"about:blank"

值得一提的是,浏览器在检查是否存在src属性之前,会先检查srcdoc是否可用,根据MDN iframe doc:

srcdoc

要嵌入的内联 HTML,覆盖 src 属性。如果浏览器不支持 srcdoc 属性,它将回退到 src 属性中的 URL。

工作示例

const container = document.getElementById("container");
const iframe = document.createElement("iframe");

iframe.addEventListener("load", function()
  console.log("loaded...");
);

iframe.srcdoc = `
  <svg  >
      <circle cx="50" cy="50" r="40" stroke="black" stroke- fill="red" />
      Sorry, your browser does not support inline SVG.  
  </svg>
`;

iframe.srcdoc += `
  <svg  >
      <circle cx="50" cy="50" r="40" stroke="black" stroke- fill="blue" />
      Sorry, your browser does not support inline SVG.  
  </svg>
`

container.append(iframe);
&lt;div id="container"&gt;&lt;/div&gt;

网络扩展解决方案

如果您正在开发网络扩展程序,您将可以访问 mozbrowser api 和 stop

HTMLIFrameElement接口的stop()方法用于停止加载&lt;iframe&gt;的内容。

【讨论】:

感谢您的详细解答!您的 tldr 表明没有可行的解决方案,但您的答案包含一个名为“工作示例”的部分,并解释说 srcdoc 应该可以工作,因为没有调用可能覆盖内联文档的加载事件。你能澄清一下吗?谢谢! 我从这个答案中的代码创建了一个codepen。我看到了两件事:a) load 事件 is 即使在使用 srcdoc 时也会生成,b) iframe 的文档在 load 被触发之前不会被填充。 @Louis 感谢您修复的评论。还修复了 tl;dir,但稍后会添加更多详细信息。希望越来越好。 嗨@kemicofa 你能澄清一下你所说的固定是什么意思吗?这个工作解决方案的代码还建议在加载事件触发之前不会填充 iframe 的文档:codepen.io/anon/pen/arROWP

以上是关于创建新的 iframe 并同步加载内容的主要内容,如果未能解决你的问题,请参考以下文章

确定 IFrame 已加载后何时呈现 iFrame 内容

检测 Iframe 内容何时加载(跨浏览器)

iframe 高度随引用的页面内容自动变化

加载后如何从 iframe 中选择内容

iFrame 高度到完整内容 [重复]

如何同步iframe与嵌入内容的高度