如何在不丢失状态的情况下移动DOM中的iFrame?

看看这个简单的HTML:

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

比方说,我想要移动换行,以使#wrap2#wrap2之前。 内嵌框架被JavaScript污染。 我知道jQuery的.insertAfter().insertAfter() .insertBefore() 。 但是,当我使用这些,iFrame失去了所有的HTML和JavaScriptvariables和事件。

比方说,以下是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> 

在上面的代码中,variablesvariableThatChanges会…如果用户点击正文,则会发生变化。 这个variables和click事件应该在iFrame被移动之后(以及其他已经启动的variables/事件)

我的问题是以下内容: 使用JavaScript(带或不带jQuery),如何移动DOM中的wrap节点(及其iframe子元素),以便iFrame的窗口保持不变,并且iFrame的events / variables / etc保留相同?

如果没有重新加载,将iframe从dom中的某个位置移动到另一个位置是不可能的。

这里是一个例子来显示,即使使用本地JavaScript的iFrames仍然重新加载: http : //jsfiddle.net/pZ23B/

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

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

很多关于w3 / dom规范的search,并没有find任何最终的具体说iframe应该重新加载,而在DOM树中移动,但是我确实在webkit的trac / bugzilla / microsoft中find了很多的参考和评论多年来不同的行为变化。

我希望有人会find关于这个问题的具体事情,但现在这里是我的发现:

  1. 据介绍说,这是预期的行为。
  2. 有一个“魔法iframe”( webkit,2010 ),但在2012年被删除 。
  3. 根据MS – “ iframe资源从DOM中移除时被释放 ”。 当你appendChild(node)的现有节点 – 该node首先从DOM中删除。
    有趣的事情在这里 – IE<=8没有重新加载iframe – 这种行为是(有点)新 (因为IE>=9 )。
  4. 根据Hallvord RM Steen的评论,这是iframe规范的引用

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

    这是我在规范中发现的最接近的东西,但是它仍然需要一些解释(因为当我们移动DOM中的iframe元素时,我们并没有真正做一个完整的remove ,即使浏览器使用node.removeChild方法) 。

每当附加一个iframe并且应用了一个src属性,它就会像通过JS创build一个Image标签一样触发一个加载操作。 所以,当你删除,然后追加他们是完全新的实体,他们刷新。 它的types如何window.location = window.location将重新加载页面。

我知道重新定位iframes的唯一方法是通过CSS。 这里是一个例子,我把它们放在一起展示了一种用flex-box处理这个问题的方法: https : //jsfiddle.net/3g73sz3k/15/

基本的想法是创build一个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样式是内联的,以简化flipbutton,所以旋转的iframes

我从这个StackOverflow问题find了解决scheme: 只用CSS交换DIV位置

希望有所帮助。

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

将iFrame附加到主体,并使用高z-索引和顶部,左侧,宽度,高度将iFrame放置到所需的位置。

即使CSS缩放工作在身体没有重新加载这是真棒!

我为我的“小部件”维护两个状态,并且使用这种方法将其注入到DOM中,或者注入到body中。

当其他内容或库将挤压或挤压您的iFrame时,这很有用。

繁荣!

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

看到我创build的这个jsfiddle提供了一个很好的testing床。 http://jsfiddle.net/RpHTj/1/

点击该框切换值。 点击“移动”来运行javascript。

这个问题是相当古老的…但我find了一种方法来移动一个iframe,而不是重新加载。 仅限CSS。 我有相机stream多个iframe,我不喜欢当他们重新加载时,我交换。 所以我使用了float,position:absolute和一些虚拟块的组合来移动它们,而不用重新加载它们,并根据需要调整所需布局(resize和全部)。

为了回应这个问题上的赏金@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); } 

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

从那里,你可以在iframe中build立login来logging状态变化,在移动dom之前,请求这个json对象。

一旦移动,iframe将重新加载,您可以将状态数据传递到iframe,iframe listen可以将数据parsing回到之前的状态。