Wie verschiebe ich einen iFrame im DOM, ohne seinen Status zu verlieren?

91

Schauen Sie sich diesen einfachen HTML-Code an:

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

Nehmen wir an, ich wollte die Wraps so verschieben, dass #wrap2sie vor dem liegen #wrap1. Die Iframes werden durch JavaScript verschmutzt. Mir sind jQuery's .insertAfter()und bekannt .insertBefore(). Wenn ich diese verwende, verliert der iFrame jedoch alle HTML- und JavaScript-Variablen und -Ereignisse.

Nehmen wir an, das Folgende war der HTML-Code des iFrame:

<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>

Im obigen Code variableThatChangeswürde sich die Variable ... ändern, wenn der Benutzer auf den Körper klickt. Diese Variable und das Klickereignis sollten nach dem Verschieben des iFrame (zusammen mit allen anderen Variablen / Ereignissen, die gestartet wurden) erhalten bleiben.

Meine Frage lautet wie folgt: Wie kann ich mit JavaScript (mit oder ohne jQuery) die Wrap-Knoten im DOM (und ihre iframe-untergeordneten Elemente) so verschieben, dass das Fenster des iFrame gleich bleibt und die Ereignisse / Variablen / etc des iFrame unverändert bleiben gleich?

JCOC611
quelle
Aktueller Fehler
Manse
@ManseUK: Die anderen Fragen haben nicht wirklich geholfen ... aber der Fehler ist ziemlich interessant.
JCOC611
1
@SalmanA Wie bewegt man einen Elternteil "um" ein Kind?
Djechlin
1
@denodster Der gewünschte Effekt vor langer Zeit, als ich diese Frage öffnete, bestand darin, die Reihenfolge einer Liste von Elementen zu ändern, die jeweils inline-blockangezeigt werden. An dieser Stelle vermute ich eine generische Lösung (oder effektiv die Aussage, dass dies unmöglich ist). wäre angesichts des Interesses anderer am angemessensten.
JCOC611

Antworten:

45

Es ist nicht möglich, einen Iframe von einem Ort im Dom an einen anderen zu verschieben, ohne ihn neu zu laden.

Hier ist ein Beispiel, um zu zeigen, dass die iFrames auch mit nativem JavaScript immer noch neu geladen werden: http://jsfiddle.net/pZ23B/

var wrap1 = document.getElementById('wrap1');
var wrap2 = document.getElementById('wrap2');
setTimeout(function(){
    document.getElementsByTagName('body')[0].appendChild(wrap1);
},10000);
Kevin B.
quelle
4
Wenn die iFrames neu geladen werden, ist dies keine Option.
JCOC611
3
Richtig, das Beispiel soll zeigen, dass die iFrames auch mit nativem JavaScript noch neu geladen werden.
Kevin B
Nun, eigentlich ist es mir wirklich egal, ob es neu geladen wird oder nicht, da sich ihre Positionen befinden about:blank, aber was mir wichtig ist, ist der Verlust des Inhalts innerhalb des Frames.
JCOC611
1
Wenn es neu geladen wird, verliert es den Inhalt im Iframe. Ich denke, Sie könnten den Inhalt im Iframe abrufen $("#iframeid").contents(), bevor Sie ihn mit jquery verschieben. Da jedoch keine gespeicherten Javascript-Daten abgerufen werden, müsste er vom Iframe an die übergeordnete Seite gesendet werden (oder die übergeordnete Seite müsste ihn abrufen der Iframe)
Kevin B
1
DelightedD0D, das Kopfgeld wurde von @djechlin eröffnet - "Ich frage mich, ob dies auch 2016 noch zutrifft", um festzustellen, ob sich in den letzten 5 Jahren in Bezug auf dieses Problem etwas geändert hat. Sie können die Zusammenfassung in meiner Antwort zu den Änderungen in diesen Jahren überprüfen.
Dekel
40

Diese Antwort bezieht sich auf das Kopfgeld von @djechlin

Viele Suchanfragen in den w3 / dom-Spezifikationen und nichts Endgültiges, das speziell besagt, dass iframe beim Verschieben im DOM-Baum neu geladen werden sollte. Ich habe jedoch viele Referenzen und Kommentare im Trac / Bugzilla / Microsoft des Webkits gefunden Unterschiedliche Verhaltensänderungen im Laufe der Jahre.

Ich hoffe, dass jemand etwas Spezifisches zu diesem Thema findet, aber im Moment sind hier meine Ergebnisse:

  1. Gemäß Ryosuke Niwa - "Das ist das erwartete Verhalten".
  2. Es gab einen "magischen Iframe " ( Webkit, 2010 ), der jedoch 2012 entfernt wurde .
  3. Laut MS - " Iframe-Ressourcen werden freigegeben, wenn sie aus dem DOM entfernt werden ". Wenn Sie appendChild(node)von vorhandenen Knoten - das nodewird zuerst aus dem Dom entfernt.
    Interessante Sache hier - IE<=8habe den Iframe nicht neu geladen - dieses Verhalten ist (etwas) neu (seit IE>=9).
  4. Laut dem Kommentar von Hallvord RM Steen ist dies ein Zitat aus den Iframe-Spezifikationen

    Wenn ein Iframe-Element in ein Dokument mit einem Browserkontext eingefügt wird, muss der Benutzeragent einen neuen Browserkontext erstellen, den verschachtelten Browserkontext des Elements auf den neu erstellten Browserkontext setzen und dann die Iframe-Attribute zum ersten Mal verarbeiten " .

    Dies ist die naheliegendste Sache, die ich in den Spezifikationen gefunden habe, erfordert jedoch noch einige Interpretationen (da wir beim Verschieben des iframeElements im DOM nicht wirklich eine vollständige Ausführung durchführen remove, selbst wenn der Browser die node.removeChildMethode verwendet).

Dekel
quelle
7
Ich freue mich über eine Antwort des Downvotters mit Erklärung.
Dekel
14

Immer wenn ein Iframe angehängt wird und ein src-Attribut angewendet wird, wird eine Ladeaktion ausgelöst, ähnlich wie beim Erstellen eines Image-Tags über JS. Wenn Sie sie entfernen und dann anhängen, handelt es sich um völlig neue Entitäten, die aktualisiert werden. Auf diese Weise window.location = window.locationwird eine Seite neu geladen.

Ich weiß nur, dass ich mich iframesüber CSS neu positionieren kann . Hier ist ein Beispiel, das ich zusammengestellt habe und das einen Weg zeigt, wie man damit umgehen kann flex-box: https://jsfiddle.net/3g73sz3k/15/

Die Grundidee besteht darin, einen flex-boxWrapper zu erstellen und dann mithilfe des order-Attributs für jeden iframe-Wrapper eine bestimmte Reihenfolge für die Iframes zu definieren.

<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>

Wie Sie in der JS-Geige sehen können, sind diese orderStile inline, um die flipSchaltfläche zu vereinfachen iframes.

Ich habe die Lösung aus dieser StackOverflow-Frage bezogen: Tauschen Sie die DIV-Position nur mit CSS aus

Hoffentlich hilft das.

PaulSCoder
quelle
1
Bounty für den ersten Absatz und die Erklärung, dass es ähnlich ist wie img und das Erstellen einer neuen Entität. nicht die CSS: P
Djechlin
So einfach und effektiv! Vielen Dank!
Stan
8

Wenn Sie den iFrame auf der Seite erstellt haben und seine Position später einfach verschieben müssen, versuchen Sie Folgendes:

Hängen Sie den iFrame an den Körper an und platzieren Sie den iFrame mit einem hohen Z-Index und oben, links, Breite und Höhe an der gewünschten Stelle.

Sogar der CSS-Zoom funktioniert am Körper ohne Nachladen, was großartig ist!

Ich behalte zwei Zustände für mein "Widget" bei und es wird entweder im DOM oder mit dieser Methode in den Körper injiziert.

Dies ist nützlich, wenn andere Inhalte oder Bibliotheken Ihren iFrame zerquetschen oder zerquetschen.

BOOM!

mattdlockyer
quelle
5

Leider ist die parentNode Eigenschaft eines HTML-DOM-Elements schreibgeschützt. Sie können natürlich die Positionen der Iframes anpassen, aber Sie können ihre Position im DOM nicht ändern und ihre Zustände beibehalten.

Sehen Sie sich diese von mir erstellte jsfiddle an, die einen guten Prüfstand bietet. http://jsfiddle.net/RpHTj/1/

Klicken Sie auf das Feld, um den Wert umzuschalten. Klicken Sie auf "Verschieben", um das Javascript auszuführen.

Matt H.
quelle
4

Diese Frage ist ziemlich alt ... aber ich habe einen Weg gefunden, einen Iframe zu verschieben, ohne ihn neu zu laden. Nur CSS. Ich habe mehrere Iframes mit Kamera-Streams. Ich mag es nicht, wenn sie neu geladen werden, wenn ich sie austausche. Also habe ich eine Kombination aus Float, Position: Absolut und einigen Dummy-Blöcken verwendet, um sie zu verschieben, ohne sie neu zu laden und bei Bedarf das gewünschte Layout zu haben (Größenänderung und alle).

moeiscool
quelle
1
Klingt nach der einzig praktikablen Option. Sie sollten die vollständige Lösung veröffentlichen, die Sie sich ausgedacht haben! Zumindest einige grundlegende Codes, um andere zum Laufen zu bringen. Vielen Dank!
JCOC611
1

Als Antwort auf das Kopfgeld, das @djechlin auf diese Frage gestellt hat, habe ich die von @ matt-h gepostete jsfiddle gegabelt und bin zu dem Schluss gekommen, dass dies immer noch nicht möglich ist.

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);
}
denodster
quelle
0

Wenn Sie den Iframe verwenden, um auf von Ihnen kontrollierte Seiten zuzugreifen, können Sie Javascript erstellen, damit Ihre Eltern über postMessage mit dem Iframe kommunizieren können

Von dort aus können Sie innerhalb des Iframes eine Anmeldung erstellen, um Statusänderungen aufzuzeichnen, und vor dem Verschieben von dom dies als JSON-Objekt anfordern.

Nach dem Verschieben wird der Iframe neu geladen. Sie können die Statusdaten an den Iframe übergeben, und das Abhören des Iframes kann die Daten wieder in den vorherigen Status zurückführen.

Drew Major
quelle
Zugegeben, dies ist eine Menge Code, setzt voraus, dass Sie alle Daten steuern, die im Frame angezeigt werden, und technisch immer noch nicht "den Status beim Verschieben in DOM beibehalten"
Drew Major