【问题标题】:How to create a cross-browser sub document with iframe or shadow dom?如何使用 iframe 或 shadow dom 创建跨浏览器子文档?
【发布时间】:2014-03-11 10:54:16
【问题描述】:

我想用 JavaScript 创建一个完全封装的子文档,有自己的<head><body>、样式、html 和 js。基本上是一个 shadow dom 或 iframe,但没有 src 属性。

虽然我喜欢 shadow dom 的想法,但它的 support is very low, 还没有准备好迎接黄金时段。

所以我一直致力于创建 iframe,但在此过程中遇到了各种障碍。 Here is a jsFiddle demonstrating my various attempts.

dom中不能存在iframe。这部分很关键。澄清一下,它暂时存在于dom中是可以的,但它必须能够被提取出来,并且只存在于js中。

$('body').append('<iframe id="iframeGenerator" />');
var iframe3 = $('#iframeGenerator');
var iframe3Contents = iframe3.contents();
$('#iframeGenerator').remove();
var head = iframe3.contents().find('head');

亲爱的,我们有头了

console.log(head.length);

但是内容是什么样的呢?

console.log(iframe3Contents.get(0));

它是一个文档,但不在元素内部 所以让我们试着把它放在 dom 或另一个元素的内部? 以下两种尝试都不起作用,因为选择器没有上下文或其他东西......

$('body').append(iframe3Contents);
var generatedIframe = $('<iframe />').append(iframe3Contents);

我希望能够在不向 dom 附加任何内容的情况下创建 iframe / subdocuemnt...但如果必须的话,我仍然希望能够随后将其从 dom 中删除并在 js 中进一步管理它。

我有这个小功能,它不起作用,但说明了我想要创建的 iframe 或子文档生成器的类型

var iframeHtml;
giveMeIframe = function() {
  var iframeContents;
  if (iframeHtml) {
    return iframeHtml;
  } else {
    $('body').append('<iframe id="iframeGenerator" style="display: none" />');
    iframeContents = $('#iframeGenerator').contents();
    iframeHtml = $('<iframe />');
    iframeHtml.append(iframeContents);
    $('#iframeGenerator').remove();
    return iframeHtml;
  }
}

【问题讨论】:

  • 试图将整个文档附加到body 是没有意义的(显然,我认为)。您在整个过程中的最终目标是什么?
  • @CBroe 我希望能够封装页面的一部分,并在 JS 中生成这些封装的部分。你是对的,试图将文档附加到body 是人​​为的,但是将它附加到 iframe,当你向 dom 添加没有 src 的 iframe 时,浏览器会以某种方式自动执行此操作,我希望这更有意义。
  • 如果你想要页面的部分,那你为什么需要一个headbody元素呢? DocumentFragment 不适用于您正在尝试做的事情......?
  • @CBroe 文档片段无法封装 css,这是我需要的。
  • @Watson,您能否将所有封装的子文档 DOM 信息提供给 html2canvas,然后将生成的 js 输出作为子文档显示在您的页面上?

标签: javascript jquery iframe shadow-dom


【解决方案1】:

我玩弄了你的小提琴并且能够让它工作。我正在使用无缝(仅限 Chrome)以使其行为更符合您正在寻找的内容,并且我有其他浏览器的 CSS 后备。

请注意,在开始编辑它的内容(添加样式和正文)之前,需要将 iframe 添加到 DOM。之后你可以删除document.body.removeChild(iframe);

您仍然可以做很多事情来使其行为与影子 DOM 元素非常相似,此演示文稿将帮助您解决问题Seamless iframes: The future, today!

JS

var styles = '<style> .pink { color: pink; width: 100px; height: 100px; } body{background-color:#eee;}</style>';

var html = '<div class="pink">PINK!</div>';

// create iframe
var iframe = document.createElement('iframe');
document.body.appendChild(iframe);

//add head and body
iframe.contentDocument.open();
iframe.contentDocument.write(styles);
iframe.contentDocument.write(html);
iframe.contentDocument.close();
iframe.setAttribute('seamless', 'seamless');

//check everything
console.log(iframe);
var head = $(iframe).contents().find('head')[0];
console.log(head);
var body = $(iframe).contents().find('body')[0];
console.log(body);

//remove from DOM
//document.body.removeChild(iframe);

CSS

iframe[seamless]{
    background-color: transparent;
    border: 0px none transparent;
    padding: 0px;
    overflow: hidden;
}

【讨论】:

  • 正如你所说,在开始编辑它的内容之前,需要将 iframe 添加到 DOM。
  • @watson 我不相信有办法解决这个问题,我认为这是因为 iframe 的使用方式。它旨在从其他页面加载内容,而不是自定义生成的 html 的包装器。但是如果你添加它然后像我一样删除它(取消注释最后一行)它不会显示在页面中。
  • 另外,您必须明白,在 shadow DOM 得到适当支持之前,没有其他方法可以在不使用 iframe 的情况下实现您的目标。您以任何其他方式加载的任何内容都将添加到 DOM 中,并从其父页面继承 CSS 规则,没有办法封装它,这就是 DOM 的工作方式。
【解决方案2】:

要从框架访问信息(或写入框架),它必须在 DOM 中。它可以被隐藏,但它仍然必须存在于框架对象中。 JQuery 通过框架对象访问 iFrame,当从 dom 中移除时,它会从框架对象中移除

为了将来参考任何偶然发现这个问题的人,您可以像这样获得封装:

$('#iframeGenerator2').contents().find('html').html(frame2HTML);

这是一个例子:http://jsfiddle.net/yP34y/4/

在 jsfiddle 示例中,请注意只有在将其添加到 DOM 后才能正常工作。

【讨论】:

  • 谢谢,我知道有很多变通方法——但你是说我想做的事是不可能的吗?如果是这样,我更喜欢一个解释为什么这是不可能的答案而不是解决方法。此外,您的小提琴中的代码也很难阅读,因为它与我的代码混在一起,并且有 3 或 4 个 iframe 在移动,您能否从小提琴中删除与您的答案无关的代码?
  • 也许我遗漏了一些东西,但您所尝试的并非不可能。这是一个更简洁的版本:jsfiddle.net/yP34y/4
  • 我认为您缺少关于“iframe 不能存在于 dom 中的部分。澄清一下,如果它暂时存在于 dom 中是可以的,但它必须能够被提取并仅存在在 JS 中。” jsfiddle.net/yP34y/5
  • 要从框架访问信息(或写入框架),它必须在 DOM 中。我在想你会创建它,添加它,操纵它,然后每次(即暂时)销毁它。 JQuery 实际上是通过框架对象访问 iFrame,当从 dom 中移除时,它会从框架对象中移除。
  • 听起来不错,唉,可能就是这样。您介意更改答案以反映您在上一条评论中所说的不可能吗?我对在这个线程中仔细阅读解决方法并不感兴趣,我只是对我们是否可以在 js 中拥有一个类似 dom 的封装 iframe 或子文档(包括头部和主体)感兴趣,而它不存在于 dom 中.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-02
  • 1970-01-01
  • 2015-06-26
  • 2012-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多