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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8318264/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 05:32:37  来源:igfitidea点击:

How to move an iFrame in the DOM without losing its state?

javascriptjquerydomiframe

提问by JCOC611

Take a look at this simple HTML:

看看这个简单的 HTML:

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

Let's say I wanted to move the wraps so that the #wrap2would be before the #wrap1. The iframes are polluted by JavaScript. I am aware of jQuery's .insertAfter()and .insertBefore(). However, when I use those, the iFrame loses all of its HTML, and JavaScript variables and events.

比方说,我想提出的面纱,以便#wrap2将之前#wrap1。iframe 被 JavaScript 污染了。我知道 jQuery.insertAfter().insertBefore(). 但是,当我使用它们时,iFrame 会丢失所有的 HTML 以及 JavaScript 变量和事件。

Lets say the following was the iFrame's HTML:

假设以下是 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>

In the above code, the variable variableThatChangeswould...change if the user clicked on the body. This variable, and the click event, should remain after the iFrame is moved (along with any other variables/events that have been started)

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

My question is the following: with JavaScript (with or without jQuery), how can I move the wrap nodes in the DOM (and their iframe childs) so that the iFrame's window stays the same, and the iFrame's events/variables/etc stay the same?

我的问题如下:使用 JavaScript(使用或不使用 jQuery),如何移动 DOM(及其 iframe 子项)中的 wrap 节点,以便 iFrame 的窗口保持不变,并且 iFrame 的事件/变量/等保持不变相同的?

采纳答案by Kevin B

It isn't possible to move an iframe from one place in the dom to another without it reloading.

不可能在不重新加载的情况下将 iframe 从 dom 中的一个位置移动到另一个位置。

Here is an example to show that even using native JavaScript the iFrames still reload: http://jsfiddle.net/pZ23B/

这是一个示例,表明即使使用本机 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);

回答by Dekel

This answer is related to the bounty by @djechlin

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

A lot of search on the w3/dom specs and didn't find anything final that specifically says that iframe should be reloaded while moving in the DOM tree, however I did find lots of references and comments in the webkit's trac/bugzilla/microsoft regarding different behavior changes over the years.

在 w3/dom 规范上进行了大量搜索,但没有找到任何最终明确指出在 DOM 树中移动时应该重新加载 iframe 的内容,但是我确实在 webkit 的 trac/bugzilla/microsoft 中找到了很多关于多年来不同的行为发生了变化。

I hope someone will find anything specific regarding this issue, but for now here are my findings:

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

  1. According to Ryosuke Niwa- "That's the expected behavior".
  2. There was a "magic iframe" (webkit, 2010), but it was removed in 2012.
  3. According to MS - "iframe resources are freed when removed from the DOM". When you appendChild(node)of existing node - that nodeis first removed from the dom.
    Interesting thing here - IE<=8didn't reload the iframe - this behavior is (somewhat) new(since IE>=9).
  4. According to Hallvord R. M. Steencomment, this is a quote from the iframe specs

    When an iframe element is inserted into a document that has a browsing context, the user agent must create a new browsing context, set the element's nested browsing context to the newly-created browsing context, and then process the iframe attributes for the "first time".

    This is the most close thing I found in the specs, however it's still require some interpretation (since when we move the iframeelement in the DOM we don't really do a full remove, even if the browsers uses the node.removeChildmethod).

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

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

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

回答by PaulSCoder

Whenever an iframe is appended and has a src attribute applied it fires a load action similarly to when creating an Image tag via JS. So when you remove and then append them they are completely new entities and they refresh. Its kind of how window.location = window.locationwill reload a page.

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

The only way I know to reposition iframesis via CSS. Here is an example I put together showing one way to handle this with flex-box: https://jsfiddle.net/3g73sz3k/15/

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

The basic idea is to create a flex-boxwrapper and then define an specific order for the iframes using the order attribute on each iframe wrapper.

基本思想是创建一个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>

As you can see in the JS fiddle these orderstyles are inline to simplify the flipbutton so rotate the iframes.

正如您在 JS fiddle 中看到的,这些order样式是内联的以简化flip按钮,因此将iframes.

I sourced the solution from this StackOverflow question: Swap DIV position with CSS only

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

Hope that helps.

希望有帮助。

回答by mattdlockyer

If you have created the iFrame on the page and simply need to move it's position later try this approach:

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

Append the iFrame to the body and use a high z-index and top,left,width,height to put the iFrame where you want.

将 iFrame 附加到正文并使用高 z-index 和 top,left,width,height 将 iFrame 放在您想要的位置。

Even CSS zoom works on the body without reloading which is awesome!

甚至 CSS 缩放也适用于身体而无需重新加载,这太棒了!

I maintain two states for my "widget" and it is either injected in place in the DOM or to the body using this method.

我为我的“小部件”维护了两种状态,它要么被注入到 DOM 中,要么使用这种方法注入到主体中。

This is useful when other content or libraries will squish or squash your iFrame.

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

BOOM!

繁荣!

回答by Matt H

Unfortunately, the parentNodeproperty of an HTML DOM element is read-only. You can adjust the positions of the iframes, of course, but you can't change their location in the DOM and preserve their states.

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

See this jsfiddle I created that provides a good test bed. http://jsfiddle.net/RpHTj/1/

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

Click on the box to toggle the value. Click on the "move" to run the javascript.

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

回答by moeiscool

This question is pretty old... but I did find a way to move an iframe without it reloading. CSS only. I have multiple iframes with camera streams, I dont like when they reload when i swap them. So i used a combination of float, position:absolute, and some dummy blocks to move them around without reloading them and having the desired layout on demand (resizing and all).

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

回答by denodster

In response to the bounty @djechlin placed on this question, I have forked the jsfiddle posted by @matt-h and have come to the conclusion that this is still not possible.

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

http://jsfiddle.net/gr3wo9u6/

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);
}

回答by Drew Major

If you are using the iframe to access pages you control, you could create some javascript to allow your parent to communicate with the iframe via postMessage

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

From there, you could build login inside the iframe to record state changes, and before moving dom, request that as a json object.

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

Once moved, the iframe will reload, you can pass the state data into the iframe and the iframe listening can parse the data back into the previous state.

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