iFrame src cambio rilevamento eventi?


181

Supponendo che non abbia alcun controllo sul contenuto dell'iframe, esiste un modo per rilevare una modifica src tramite la pagina principale? Una sorta di onload forse?

La mia ultima risorsa è fare un test a intervalli di 1 secondo se iframe src è lo stesso di prima, ma fare questa soluzione hacky farebbe schifo.

Sto usando la libreria jQuery se aiuta.


3
La srcproprietà cambierà quando si fa clic su un collegamento nell'iframe? Non ne sono sicuro - se dovessi indovinare, se direi "no". Ci sono modi per proprietà del monitor (in Firefox almeno per quanto ne so), ma non sono sicuro se sarà di qualche utilità in questo caso.
Pekka,

Sto cercando di implementare qualcosa del genere e posso confermare che l' srcattributo nel DOM non cambia nelle ultime versioni di FireFox o Safari. @ La risposta di Michiel qui sotto è buona quanto sono stato in grado di arrivare così lontano.
Kaelin Colclasure,

Risposte:


201

È possibile che si desideri utilizzare l' onLoadevento, come nell'esempio seguente:

<iframe src="http://www.google.com/" onLoad="alert('Test');"></iframe>

L'avviso verrà visualizzato ogni volta che cambia la posizione all'interno dell'iframe. Funziona con tutti i browser moderni, ma potrebbe non funzionare con alcuni browser molto vecchi come IE5 e Early Opera. ( Fonte )

Se l'iframe mostra una pagina all'interno dello stesso dominio del genitore , si sarebbe in grado di accedere alla posizione con contentWindow.location, come nell'esempio seguente:

<iframe src="/test.html" onLoad="alert(this.contentWindow.location);"></iframe>

13
Intendi this.contentWindow.location.href
Nikolai,

@Daniel Vassallo supponendo che tu prenda questo approccio quando desideri gestire il problema di sicurezza, non riesci a qualcuno a ignorare l'evento onLoad e quindi a modificare il contenuto iframe?
Noam Shaish,

15
Quando lo faccio this.contentWindow.location.hrefottengoPermission denied to access property 'href'
Mazatec il

4
this.contentWindow.location.href non funzionerà perché stai facendo una richiesta di origine incrociata. :( Tutti i browser ora lo limitano.
Naveen,

2
Correzione: this.contentWindow.locationè disponibile per altri domini. Anche this.contentWindow.location.hrefè disponibile per altri domini, ma solo per la scrittura. Tuttavia, la lettura this.contentWindow.location.hrefè limitata allo stesso dominio.
wadim,

57

Risposta basata su JQuery <3

$('#iframeid').load(function(){
    alert('frame has (re)loaded');
});

Come indicato da subharb, a partire da JQuery 3.0 questo deve essere modificato in:

$('#iframe').on('load', function() {
    alert('frame has (re)loaded ');
});

https://jquery.com/upgrade-guide/3.0/#breaking-change-load-unload-and-error-removed


3
Non funziona esattamente come previsto. Emette l'avviso al caricamento della pagina iniziale. A seconda di quali sono i tuoi piani per questo codice (per me, sto animando la finestra di dialogo dalla pagina al momento dell'invio del modulo) questa soluzione non funzionerà.
Stacigh,

@stracigh, questo è corretto, l'evento si attiva ogni volta che viene caricato il frame, quindi anche la prima volta sul caricamento della pagina iniziale. Se non si desidera che il codice venga attivato la prima volta, è necessario in qualche modo rilevare che si tratta del primo caricamento e ritorno del frame.
Michiel,

@FooBar, Sì, funziona su più domini, infatti è quello per cui l'ho usato. Ma non puoi accedere alla pagina nell'iFrame con javascript quando quella pagina si trova su un altro dominio.
Michiel,

questo funziona e rileva quando il contenuto viene caricato, ho bisogno di un modo per rilevare quando l'src sta cambiando. Qualcosa come prima di caricare (per attivare un caricatore)
Andrea_86

Come indicato da @stacigh, verrà generato l'evento una volta sul caricamento della pagina padre. Se dichiari un contatore esterno a quella funzione e lo leggi all'interno, puoi successivamente rilevare le modifiche. Dovresti incrementare il contatore all'interno del gestore onload più avere if (counter > 1) { // do something on iframe actual change }(supponendo che il contatore fosse impostato su 0 all'inizio)
Alex

38

Se non hai alcun controllo sulla pagina e desideri vedere qualche tipo di modifica, utilizza il metodo moderno MutationObserver

Un esempio del suo utilizzo, cercando l' srcattributo per cambiare di uniframe

new MutationObserver(function(mutations) {
  mutations.some(function(mutation) {
    if (mutation.type === 'attributes' && mutation.attributeName === 'src') {
      console.log(mutation);
      console.log('Old src: ', mutation.oldValue);
      console.log('New src: ', mutation.target.src);
      return true;
    }

    return false;
  });
}).observe(document.body, {
  attributes: true,
  attributeFilter: ['src'],
  attributeOldValue: true,
  characterData: false,
  characterDataOldValue: false,
  childList: false,
  subtree: true
});

setTimeout(function() {
  document.getElementsByTagName('iframe')[0].src = 'http://jsfiddle.net/';
}, 3000);
<iframe src="http://www.google.com"></iframe>

Uscita dopo 3 secondi

MutationRecord {oldValue: "http://www.google.com", attributeNamespace: null, attributeName: "src", nextSibling: null, previousSibling: null…}
Old src:  http://www.google.com
New src:  http://jsfiddle.net/ 

Su jsFiddle

La risposta inserita qui come domanda originale è stata chiusa come duplicato di questo.


Che cosa succede se sto utilizzando Web Components e uno dei miei componenti personalizzati ha un attributo src? Penso che questo lo prenderebbe accidentalmente.
Luca

Quindi si cambiano le opzioni su observe. Questo è solo un esempio.
Xotic750,

@PaulRoub ha rimosso il collegamento jsfiddle (deve essere stato un errore di copia / incolla) e ha incluso il codice come frammento.
Xotic750,

4
Ma nel mio caso, il frame.contentDocument.URL cambia (dai collegamenti all'interno del frame) non lo src. Posso vederlo?
httpete

Non sono sicuro, meglio scrivere una domanda, penso.
Xotic750,

11

Nota: lo snippet funzionerebbe solo se l'iframe avesse la stessa origine.

Altre risposte hanno proposto l' loadevento, ma si attiva dopo il caricamento della nuova pagina nell'iframe. Potrebbe essere necessario ricevere una notifica immediatamente dopo la modifica dell'URL , non dopo il caricamento della nuova pagina.

Ecco una semplice soluzione JavaScript:

function iframeURLChange(iframe, callback) {
    var unloadHandler = function () {
        // Timeout needed because the URL changes immediately after
        // the `unload` event is dispatched.
        setTimeout(function () {
            callback(iframe.contentWindow.location.href);
        }, 0);
    };

    function attachUnload() {
        // Remove the unloadHandler in case it was already attached.
        // Otherwise, the change will be dispatched twice.
        iframe.contentWindow.removeEventListener("unload", unloadHandler);
        iframe.contentWindow.addEventListener("unload", unloadHandler);
    }

    iframe.addEventListener("load", attachUnload);
    attachUnload();
}

iframeURLChange(document.getElementById("mainframe"), function (newURL) {
    console.log("URL changed:", newURL);
});
<iframe id="mainframe" src=""></iframe>

In questo modo verranno monitorate correttamente le srcmodifiche agli attributi, nonché eventuali modifiche all'URL apportate dall'iframe stesso.

Testato su tutti i browser moderni.

Ho fatto anche un'idea con questo codice. Puoi controllare anche la mia altra risposta . Approfondisce il modo in cui funziona.


6

L'iframe mantiene sempre la pagina padre, dovresti usarlo per rilevare in quale pagina sei nell'iframe:

Codice HTML:

<iframe id="iframe" frameborder="0" scrolling="no" onload="resizeIframe(this)" width="100%" src="www.google.com"></iframe>

js:

    function resizeIframe(obj) {
        alert(obj.contentWindow.location.pathname);
    }

2

Dalla versione 3.0 di Jquery potresti ricevere un errore

TypeError: url.indexOf non è una funzione

Che può essere facilmente risolto facendo

$('#iframe').on('load', function() {
    alert('frame has (re)loaded ');
});

1

Ecco il metodo utilizzato in Commerce SagePay e nei moduli Commerce Paypoint Drupal che fondamentalmente si confronta document.location.hrefcon il vecchio valore caricando prima il proprio iframe, quindi uno esterno.

Quindi in sostanza l'idea è quella di caricare la pagina vuota come segnaposto con il proprio codice JS e la sua forma nascosta. Quindi il codice JS padre invierà quella forma nascosta dove #actionpunta all'iframe esterno. Una volta che si verifica il reindirizzamento / invio, il codice JS che è ancora in esecuzione su quella pagina può tenere traccia delle document.location.hrefmodifiche del valore.

Ecco l'esempio JS utilizzato in iframe:

;(function($) {
  Drupal.behaviors.commercePayPointIFrame = {
    attach: function (context, settings) {
      if (top.location != location) {
        $('html').hide();
        top.location.href = document.location.href;
      }
    }
  }
})(jQuery);

Ed ecco JS usato nella pagina principale:

;(function($) {
  /**
   * Automatically submit the hidden form that points to the iframe.
   */
  Drupal.behaviors.commercePayPoint = {
    attach: function (context, settings) {
      $('div.payment-redirect-form form', context).submit();
      $('div.payment-redirect-form #edit-submit', context).hide();
      $('div.payment-redirect-form .checkout-help', context).hide();
    }
  }
})(jQuery);

Quindi nella pagina di destinazione vuota temporanea è necessario includere il modulo che reindirizzerà alla pagina esterna.


Questo può essere un trucco, ma il sovraccarico è notevolmente inferiore all'osservatore di mutazione. Se utilizzato in un'applicazione a pagina singola, prestare attenzione a non creare riferimenti che impediscano la raccolta dei rifiuti dagli avanzi di questo hack.
Jeff
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.