如何在DOM中移动iFrame而不丢失其状态?


93

看一下这个简单的HTML:

<div id="wrap1">
  <iframe id="iframe1"></iframe>
</div>
<div id="warp2">
  <iframe id="iframe2"></iframe>
</div>

假设我想移动包装纸,使包装纸位于#wrap2之前#wrap1。iframe被JavaScript污染了。我知道jQuery的.insertAfter().insertBefore()。但是,当我使用它们时,iFrame会丢失其所有HTML,JavaScript变量和事件。

可以说以下是iFrame的HTML:

<html>
  <head>
    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript">
      // The variable below would change on click
      // This represents changes on variables after the code is loaded
      // These changes should remain after the iFrame is moved
      variableThatChanges = false;
      $(function(){
        $("body").click(function(){ 
          variableThatChanges = true; 
        });
      });
    </script>
  </head>
  <body>
    <div id='anything'>Illustrative Example</div>
  </body>
</html>

在上面的代码中,变量 variableThatChanges如果用户单击主体将...更改。移动iFrame之后,此变量和click事件应保留(以及已启动的任何其他变量/事件)

我的问题是:使用JavaScript(带有或不带有jQuery),如何在DOM(及其iframe子级)中移动包装节点,以使iFrame的窗口保持不变,而iFrame的事件/变量/等保持不变。相同?



Mozilla当前引发的错误... bugzilla.mozilla.org/show_bug.cgi?id=254144
Manse

@ManseUK:其他问题并没有真正帮助...但是该错误非常有趣。
JCOC611

1
@SalmanA您如何移动父母“绕过”一个孩子?
djechlin

1
@denodster,当我打开这个问题时,理想的效果是改变元素列表的顺序,每个元素都带有inline-block显示...在这一点上,我正在猜测一个通用的解决方案(或者有效地声明这是不可能的)考虑到其他人的利益,这将是最合适的。
JCOC611

Answers:


46

如果不重新加载,则无法将iframe从dom中的一个位置移动到另一个位置。

以下示例说明即使使用本机JavaScript,iFrame仍会重新加载:http : //jsfiddle.net/pZ23B/

var wrap1 = document.getElementById('wrap1');
var wrap2 = document.getElementById('wrap2');
setTimeout(function(){
    document.getElementsByTagName('body')[0].appendChild(wrap1);
},10000);

4
好吧,如果iFrame重新加载,则不是一种选择。
JCOC611

3
正确,该示例的目的是表明即使使用本机JavaScript,iFrame仍会重新加载。
凯文B

好吧,实际上,我真的不在乎它是否重新加载,因为它们的位置是about:blank,但是我关心的是丢失框架内的内容。
JCOC611

1
如果重新加载,将导致其丢失iframe中的内容。我猜想您可以在使用jquery移动iframe之前在iframe中抓取内容,$("#iframeid").contents()但是不会获取已存储的javascript数据,它必须由iframe发送到父页面。(否则父页面必须从中抓取它iframe)
Kevin B

1
DedjedD0D的赏金由@djechlin打开-“我想知道在2016年是否仍然如此”,以查看过去5年在此问题上是否有任何变化。您可以在我的答案中查看有关这些年来的变化的摘要。
Dekel

40

这个答案与@djechlin的赏金有关

在w3 / dom规范上进行了大量搜索,没有找到任何最终说明iframe在DOM树中移动时应重新加载iframe的最终结果,但是我确实在webkit的Trac / bugzilla / microsoft中找到了许多参考和评论,多年来不同的行为变化。

我希望有人能找到有关此问题的任何具体信息,但是现在这是我的发现:

  1. Niwa Ryosuke称 -“这是预期的行为”。
  2. 曾经有一个“神奇的iframe”(Webkit,2010年),但在2012年删除了
  3. 根据MS的说法:“ 从DOM中删除iframe资源后,它会被释放 ”。当您appendChild(node)拥有现有节点时- node首先从dom中删除。
    有趣的是- IE<=8没有重新加载iframe-这种行为(有点)是新的(因为IE>=9)。
  4. 根据Hallvord RM Steen的评论,这是iframe规范的报价

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

    这是我在规范中找到的最接近的内容,但是仍然需要一些解释(因为当我们iframe在DOM中移动元素时remove,即使浏览器使用该node.removeChild方法,我们也不会真正完成操作)。


7
将会感谢下降投票者的回复并提供解释。
Dekel

14

每当附加iframe并应用src属性时,都会触发加载操作,类似于通过JS创建Image广告代码时。因此,当您删除然后附加它们时,它们是全新的实体,它们会刷新。这类如何window.location = window.location重新加载页面。

我知道重新定位的唯一方法iframes是通过CSS。这是我放在一起的示例,展示了一种使用以下方法来处理此问题的方法flex-boxhttps : //jsfiddle.net/3g73sz3k/15/

基本思想是创建一个flex-box包装器,然后使用每个iframe包装器上的order属性为iframe定义特定的顺序。

<style>
  .container{
    display: flex;
    flex-direction: column;
  }
</style>
<div class="container">
  <div id="wrap1" style="order: 0" class="iframe-wrapper">
    <iframe id="iframe1" src="https://google.com"></iframe>
  </div>
  <div id="warp2" style="order: 1" class="iframe-wrapper">
    <iframe id="iframe2" src="https://bing.com"></iframe>
  </div>
</div>

正如您在JS小提琴中看到的那样,这些order样式是内联的,以简化flip按钮,因此请旋转iframes

我从这个StackOverflow问题中获取了解决方案:仅使用CSS交换DIV位置

希望能有所帮助。


1
赏金第一段,并解释它类似于img和创建新实体。而不是CSS:P
djechlin '16

如此简单有效!非常感谢你!
斯坦(Stan)

8

如果您在页面上创建了iFrame,只是稍后需要移动它的位置,请尝试以下方法:

将iFrame附加到主体上,并使用较高的z-index和top,left,width,height将iFrame放置在所需位置。

甚至CSS缩放都可以在主体上运行而无需重新加载,这真是太棒了!

我为“小部件”维护两个状态,并且使用此方法将其注入到DOM中或注入到主体中。

当其他内容或库将挤压或挤压iFrame时,此功能很有用。

繁荣!


5

不幸的是, parentNode HTML DOM元素属性是只读的。当然,您可以调整iframe的位置,但不能更改其在DOM中的位置并保留其状态。

请参阅我创建的这个jsfiddle,它提供了很好的测试平台。http://jsfiddle.net/RpHTj/1/

单击框以切换值。单击“移动”以运行javascript。


4

这个问题已经很老了……但是我确实找到了一种无需重新加载即可移动iframe的方法。仅CSS。我有多个带相机流的iframe,我不喜欢在交换它们时重新加载它们。因此,我使用了float,position:absolute和一些虚拟块的组合来移动它们,而无需重新加载它们并按需具有所需的布局(调整大小和全部)。


1
听起来是唯一可行的选择。您应该发布完整的解决方案!至少需要一些基本代码才能使其他人入门。谢谢!
JCOC611 '16

1

为了回应对这个问题的赏金@djechlin,我分叉了@ matt-h发布的jsfiddle,得出的结论是仍然不可能。

http://jsfiddle.net/gr3wo9u6/

//this does not work, the frames reload when appended back to the DOM
function swapFrames() {
    var w1 = document.getElementById('wrap1');
    var w2 = document.getElementById('wrap2');
    var f1 = w1.querySelector('iframe');
    var f2 = w2.querySelector('iframe');

    w1.removeChild(f1);
    w2.removeChild(f2);
    w1.appendChild(f2);
    w2.appendChild(f1);
    //f1.parentNode = w2;
    //f2.parentNode = w1;

    //alert(f1.parentNode.id);
}

0

如果您使用iframe访问您控制的页面,则可以创建一些JavaScript,以允许您的父母通过postMessage与iframe进行通信

从那里,您可以在iframe中建立登录以记录状态更改,并在移动dom之前将其请求为json对象。

移动后,iframe将重新加载,您可以将状态数据传递到iframe中,而iframe侦听可以将数据解析回先前的状态。


当然,这是很多代码,假设您控制了将在框架中显示的所有数据,但从技术上讲,它仍然不会“在DOM中移动时保持状态”
Drew Major
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.