web-dev-qa-db-fra.com

Comment déplacer un iFrame dans le DOM sans perdre son état?

Jetez un œil à ce simple HTML:

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

Supposons que je veuille déplacer les wraps pour que le #wrap2 Soit avant le #wrap1. Les iframes sont pollués par JavaScript. Je connais .insertAfter() et .insertBefore() de jQuery. Cependant, lorsque j'utilise ceux-ci, l'iFrame perd tout son HTML et ses variables et événements JavaScript.

Disons que ce qui suit était le HTML de l'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>

Dans le code ci-dessus, la variable variableThatChanges changerait ... si l'utilisateur cliquait sur le corps. Cette variable et l'événement de clic doivent rester après le déplacement de l'iFrame (avec toutes les autres variables/événements qui ont été démarrés)

Ma question est la suivante: avec JavaScript (avec ou sans jQuery), comment puis-je déplacer les nœuds d'habillage dans le DOM (et leurs enfants iframe) afin que la fenêtre de l'iFrame reste la même, et les événements/variables de l'iFrame/etc reste le même?

84
JCOC611

Il n'est pas possible de déplacer un iframe d'un endroit dans le dom à un autre sans le recharger.

Voici un exemple pour montrer que même en utilisant JavaScript natif, les iFrames se rechargent toujours: http://jsfiddle.net/pZ23B/

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

Cette réponse est liée à la prime de @djechlin

Beaucoup de recherches sur les spécifications w3/dom et je n'ai rien trouvé de final qui dit spécifiquement que l'iframe doit être rechargé lors du déplacement dans l'arborescence DOM, mais j'ai trouvé beaucoup de références et de commentaires dans le trac/bugzilla/Microsoft du webkit concernant différents changements de comportement au fil des ans.

J'espère que quelqu'un trouvera quelque chose de spécifique concernant ce problème, mais pour l'instant voici mes conclusions:

  1. Selon Ryosuke Niwa - "C'est le comportement attendu".
  2. Il y avait un "iframe magique" ( webkit, 201 ), mais c'était supprimé en 2012 .
  3. Selon MS - " les ressources iframe sont libérées lorsqu'elles sont supprimées du DOM ". Lorsque vous appendChild(node) du nœud existant - que node est d'abord supprimé du dom.
    Chose intéressante ici - IE<=8 n'a pas rechargé l'iframe - ce comportement est (quelque peu) nouveau (puisque IE>=9).
  4. Selon Hallvord R. M. Steen commentaire, ceci est une citation des spécifications iframe

    Lorsqu'un élément iframe est inséré dans un document qui a un contexte de navigation, l'agent utilisateur doit créer un nouveau contexte de navigation, définir le contexte de navigation imbriqué de l'élément sur le contexte de navigation nouvellement créé, puis traiter les attributs iframe pour la "première fois" .

    C'est la chose la plus proche que j'ai trouvée dans les spécifications, mais cela nécessite encore une certaine interprétation (car lorsque nous déplaçons l'élément iframe dans le DOM, nous ne faisons pas vraiment un remove complet, même si les navigateurs utilisent le node.removeChild méthode).

36
Dekel

Chaque fois qu'un iframe est ajouté et qu'un attribut src est appliqué, il déclenche une action de chargement de la même manière que lors de la création d'une balise Image via JS. Ainsi, lorsque vous les supprimez puis les ajoutez, ce sont de nouvelles entités et elles sont actualisées. Son genre de comment window.location = window.location rechargera une page.

Le seul moyen que je connaisse pour repositionner iframes est via CSS. Voici un exemple que j'ai mis en place montrant une façon de gérer cela avec flex-box: https://jsfiddle.net/3g73sz3k/15/

L'idée de base est de créer un flex-box wrapper, puis définissez un ordre spécifique pour les iframes à l'aide de l'attribut order sur chaque wrapper 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>

Comme vous pouvez le voir dans le violon JS, ces styles order sont en ligne pour simplifier le bouton flip donc tournez le iframes.

J'ai trouvé la solution de cette question StackOverflow: Swap DIV position with CSS only

J'espère que ça t'as aidé.

13
PaulSCoder

Si vous avez créé l'iFrame sur la page et que vous devez simplement déplacer sa position plus tard, essayez cette approche:

Ajoutez l'iFrame au corps et utilisez un indice z élevé et en haut, à gauche, largeur, hauteur pour placer l'iFrame où vous voulez.

Même le zoom CSS fonctionne sur le corps sans rechargement, ce qui est génial!

Je maintiens deux états pour mon "widget" et il est soit injecté en place dans le DOM ou au corps en utilisant cette méthode.

Ceci est utile lorsque d'autres contenus ou bibliothèques écraseront ou écraseront votre iFrame.

BOOM!

8
mattdlockyer

Malheureusement, la propriété parentNode d'un élément HTML DOM est en lecture seule. Vous pouvez bien sûr ajuster la position des iframes, mais vous ne pouvez pas modifier leur emplacement dans le DOM et conserver leurs états.

Voir ce jsfiddle que j'ai créé qui fournit un bon banc d'essai. http://jsfiddle.net/RpHTj/1/

Cliquez sur la case pour basculer la valeur. Cliquez sur "déplacer" pour exécuter le javascript.

5
Matt H

Cette question est assez ancienne ... mais j'ai trouvé un moyen de déplacer un iframe sans le recharger. CSS uniquement. J'ai plusieurs iframes avec des flux de caméras, je n'aime pas quand ils se rechargent quand je les échange. J'ai donc utilisé une combinaison de flottant, de position: absolu et de blocs factices pour les déplacer sans les recharger et avoir la mise en page souhaitée à la demande (redimensionnement et tout).

4
moeiscool

En réponse à la prime @djechlin placée sur cette question, j'ai bifurqué le jsfiddle publié par @ matt-h et suis arrivé à la conclusion que ce n'est toujours pas possible.

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

Si vous utilisez l'iframe pour accéder aux pages que vous contrôlez, vous pouvez créer du javascript pour permettre à vos parents de communiquer avec l'iframe via postMessage

De là, vous pouvez créer une connexion à l'intérieur de l'iframe pour enregistrer les changements d'état et, avant de déplacer dom, demander cela en tant qu'objet json.

Une fois déplacé, l'iframe se rechargera, vous pouvez passer les données d'état dans l'iframe et l'écoute iframe peut réanalyser les données dans l'état précédent.

0
Drew Major