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

时间:2011-11-29 21:53:46

标签: javascript jquery dom iframe

看看这个简单的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的事件/ variables / etc保持不变?

8 个答案:

答案 0 :(得分:42)

如果没有重新加载,就无法将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);

答案 1 :(得分:35)

  

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

在w3 / dom规范上进行了很多搜索,并没有找到任何特别说明iframe应该在DOM树中移动时重新加载的内容,但是我确实在webkit的trac / bugzilla中找到了很多引用和注释/ microsoft关于多年来不同行为的变化。

我希望有人能找到有关这个问题的具体内容,但现在我的调查结果如下:

  1. 根据Ryosuke Niwa - “这是预期的行为”。
  2. 有一个“神奇的iframe”(webkit, 2010),但它是removed in 2012
  3. 根据MS - “iframe resources are freed when removed from the DOM”。当您appendChild(node)现有节点时 - node首先从dom中移除。
    有趣的是 - IE<=8没有重新加载iframe - 这种行为(有点)是新的(从IE>=9开始)。
  4. 根据Hallvord R. M. Steen评论,这是iframe specs

    的引用
      

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

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

答案 2 :(得分:12)

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

我知道重新定位iframes的唯一方法是通过CSS。这是我放在一起的示例,显示了使用flex-box处理此问题的一种方法: https://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问题中获取了解决方案:Swap DIV position with CSS only

希望有所帮助。

答案 3 :(得分:6)

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

将iFrame附加到正文并使用高z-index和顶部,左侧,宽度,高度将iFrame放在您想要的位置。

即使是CSS缩放也可以在没有重新加载的情况下在身体上运行,这很棒!

我为我的“小部件”维护了两种状态,它使用此方法注入到DOM或身体中。

当其他内容或图书馆挤压或挤压您的iFrame时,此功能非常有用。

BOOM!

答案 4 :(得分:5)

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

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

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

答案 5 :(得分:4)

这个问题很老了......但是我确实找到了一种方法来移动iframe而不重新加载。仅限CSS。我有多个带有相机流的iframe,当我交换它们时我不喜欢它们重新加载。所以我使用了float,position:absolute和一些虚拟块的组合来移动它们而不重新加载它们并根据需要设置所需的布局(调整大小等等)。

答案 6 :(得分: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);
}

答案 7 :(得分:0)

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

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

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