Come spostare un iFrame nel DOM senza perdere il suo stato?


93

Dai un'occhiata a questo semplice HTML:

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

Diciamo che volevo spostare gli involucri in modo che #wrap2fosse prima del file #wrap1. Gli iframe sono inquinati da JavaScript. Sono a conoscenza di jQuery .insertAfter()e .insertBefore(). Tuttavia, quando li uso, l'iFrame perde tutte le sue variabili ed eventi HTML e JavaScript.

Diciamo che il seguente era l'HTML dell'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>

Nel codice sopra, la variabile variableThatChangescambierebbe ... se l'utente facesse clic sul corpo. Questa variabile e l'evento clic devono rimanere dopo lo spostamento dell'iFrame (insieme a qualsiasi altra variabile / evento che è stato avviato)

La mia domanda è la seguente: con JavaScript (con o senza jQuery), come posso spostare i nodi di wrap nel DOM (e i loro figli iframe) in modo che la finestra dell'iFrame rimanga la stessa e gli eventi / variabili / ecc dell'iFrame rimangano stesso?



Bug attuale sollevato con Mozilla ... bugzilla.mozilla.org/show_bug.cgi?id=254144
Manse

@ ManeUK: le altre domande non sono state d'aiuto ... ma il bug è piuttosto interessante.
JCOC611

1
@SalmanA come fai a spostare un genitore "in giro" per un bambino?
Djechlin

1
@denodster l'effetto desiderato quando ho aperto questa domanda era cambiare l'ordine di un elenco di elementi, ciascuno con inline-blockdisplay ... a questo punto, immagino una soluzione generica (o effettivamente l'affermazione che tale è impossibile) sarebbe più appropriato, dato l'interesse degli altri.
JCOC611

Risposte:


46

Non è possibile spostare un iframe da un punto a un altro nel dom senza ricaricarlo.

Ecco un esempio per mostrare che anche utilizzando JavaScript nativo gli iFrame si ricaricano ancora: http://jsfiddle.net/pZ23B/

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

4
Bene, se gli iFrame si ricaricano, non è un'opzione.
JCOC611

3
Bene, lo scopo dell'esempio è mostrare che anche utilizzando JavaScript nativo gli iFrame si ricaricano ancora.
Kevin B

Beh, in realtà, non mi interessa davvero se si ricarica o meno, dal momento che le loro posizioni lo sono about:blank, ma quello che mi interessa è perdere il contenuto all'interno del frame.
JCOC611

1
se si ricarica, perderebbe il contenuto all'interno dell'iframe. Immagino che potresti prendere il contenuto all'interno dell'iframe prima di spostarlo usando jquery, $("#iframeid").contents()tuttavia ciò non otterrà i dati javascript memorizzati, dovrebbe essere inviato alla pagina genitore dall'iframe. (O la pagina genitore dovrebbe prenderlo da l'iframe)
Kevin B

1
DelightedD0D, il premio è stato aperto da @djechlin - "Mi chiedo se questo sia ancora vero nel 2016" per vedere se negli ultimi 5 anni è cambiato qualcosa riguardo a questo problema. Puoi controllare il riepilogo nella mia risposta riguardo ai cambiamenti avvenuti in questi anni.
Dekel

40

Questa risposta è correlata alla taglia di @djechlin

Molte ricerche sulle specifiche w3 / dom e non ho trovato nulla di finale che dica specificamente che iframe dovrebbe essere ricaricato mentre ci si sposta nell'albero DOM, tuttavia ho trovato molti riferimenti e commenti nel trac / bugzilla / microsoft del webkit riguardo diversi cambiamenti di comportamento nel corso degli anni.

Spero che qualcuno trovi qualcosa di specifico riguardo a questo problema, ma per ora ecco le mie scoperte:

  1. Secondo Ryosuke Niwa - "Questo è il comportamento previsto".
  2. C'era un "iframe magico" ( webkit, 2010 ), ma è stato rimosso nel 2012 .
  3. Secondo MS - "le risorse iframe vengono liberate quando vengono rimosse dal DOM ". Quando si tratta appendChild(node)di un nodo esistente, che nodeviene prima rimosso dal dominio.
    Cosa interessante qui - IE<=8non ho ricaricato l'iframe - questo comportamento è (un po ') nuovo (da allora IE>=9).
  4. Secondo il commento di Hallvord RM Steen , questa è una citazione dalle specifiche dell'iframe

    Quando un elemento iframe viene inserito in un documento che ha un contesto di navigazione, l'agente utente deve creare un nuovo contesto di navigazione, impostare il contesto di navigazione nidificato dell'elemento sul contesto di navigazione appena creato, e quindi elaborare gli attributi iframe per la "prima volta " .

    Questa è la cosa più vicina che ho trovato nelle specifiche, tuttavia richiede ancora qualche interpretazione (poiché quando spostiamo l' iframeelemento nel DOM non ne facciamo un completo remove, anche se i browser utilizzano il node.removeChildmetodo).


7
Apprezzerò una risposta dal downvoter con spiegazione.
Dekel

14

Ogni volta che un iframe viene aggiunto e ha un attributo src applicato, attiva un'azione di caricamento simile a quando si crea un tag immagine tramite JS. Quindi, quando li rimuovi e poi li aggiungi, sono entità completamente nuove e si aggiornano. Il suo tipo di come window.location = window.locationricaricherà una pagina.

L'unico modo che conosco per riposizionare iframesè tramite CSS. Ecco un esempio che ho messo insieme che mostra un modo per gestirlo con flex-box: https://jsfiddle.net/3g73sz3k/15/

L'idea di base è creare un flex-boxwrapper e quindi definire un ordine specifico per gli iframe utilizzando l'attributo order su ogni 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>

Come puoi vedere nel violino JS, questi orderstili sono in linea per semplificare il flippulsante, quindi ruota il iframes.

Ho preso la soluzione da questa domanda StackOverflow: scambia la posizione DIV solo con CSS

Spero che aiuti.


1
Bounty per il primo paragrafo e spiegando che è simile a img e alla creazione di una nuova entità. non il css: P
djechlin

Così semplice ed efficace! Grazie mille!
Stan

8

Se hai creato l'iFrame sulla pagina e devi semplicemente spostare la sua posizione in un secondo momento, prova questo approccio:

Aggiungi l'iFrame al corpo e usa un indice z alto e in alto, a sinistra, in larghezza, in altezza per posizionare l'iFrame dove vuoi.

Anche lo zoom CSS funziona sul corpo senza ricaricare, il che è fantastico!

Mantengo due stati per il mio "widget" e viene iniettato sul posto nel DOM o nel corpo utilizzando questo metodo.

Ciò è utile quando altri contenuti o librerie schiacciano o schiacciano il tuo iFrame.

BOOM!


5

Sfortunatamente, la parentNodeproprietà di un elemento HTML DOM è di sola lettura. Puoi regolare le posizioni degli iframe, ovviamente, ma non puoi modificare la loro posizione nel DOM e preservarne lo stato.

Guarda questo jsfiddle che ho creato che fornisce un buon banco di prova. http://jsfiddle.net/RpHTj/1/

Fare clic sulla casella per alternare il valore. Fare clic su "sposta" per eseguire il javascript.


4

Questa domanda è piuttosto vecchia ... ma ho trovato un modo per spostare un iframe senza ricaricarlo. Solo CSS. Ho più iframe con flussi di telecamere, non mi piace quando si ricaricano quando li scambio. Quindi ho usato una combinazione di float, position: absolute e alcuni blocchi fittizi per spostarli senza ricaricarli e avere il layout desiderato su richiesta (ridimensionamento e tutto).


1
Sembra l'unica opzione praticabile. Dovresti pubblicare la soluzione completa che hai trovato! Almeno un po 'di codice di base per far iniziare gli altri. Grazie!
JCOC611

1

In risposta alla generosità che @djechlin ha posto su questa domanda, ho biforcato il jsfiddle postato da @ matt-h e sono giunto alla conclusione che questo non è ancora possibile.

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

0

Se utilizzi l'iframe per accedere alle pagine che controlli, potresti creare un po 'di javascript per consentire ai tuoi genitori di comunicare con l'iframe tramite postMessage

Da lì, puoi creare un login all'interno dell'iframe per registrare i cambiamenti di stato e, prima di spostare dom, richiederlo come oggetto json.

Una volta spostato, l'iframe verrà ricaricato, puoi passare i dati di stato nell'iframe e l'iframe in ascolto può analizzare i dati nello stato precedente.


Certo, questo è un sacco di codice, presuppone che tu controlli tutti i dati che verranno visualizzati nel frame e ancora tecnicamente non "mantiene lo stato durante lo spostamento in DOM"
Drew Major
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.