iFrame src ¿detección de eventos de cambio?


Asumiendo que no tengo control sobre el contenido en el iframe, ¿hay alguna manera de que pueda detectar un cambio de src en él a través de la página principal? ¿Algún tipo de carga tal vez?

Mi último recurso es hacer una prueba de intervalo de 1 segundo si el iframe src es el mismo que antes, pero hacer esta solución hacky sería una mierda.

Estoy usando la biblioteca jQuery si ayuda.

Author: Matrym, 2010-03-12

7 answers

Es posible que desee utilizar el evento onLoad, como en el siguiente ejemplo:

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

La alerta aparecerá cada vez que cambie la ubicación dentro del iframe. Funciona en todos los navegadores modernos, pero puede que no funcione en algunos navegadores muy antiguos como IE5 y early Opera. (Fuente )

Si el iframe muestra una página dentro del mismo dominio del padre, podrá acceder a la ubicación con contentWindow.location, como en el siguiente ejemplo:

<iframe src="/test.html" onLoad="alert(this.contentWindow.location);"></iframe>
 164
Author: Daniel Vassallo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-18 18:54:21

Respuesta basada en jQuery

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

Como se menciona en subharb, a partir de jQuery 3.0 esto debe cambiarse a:

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

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

 50
Author: Michiel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-21 09:55:25

Si no tiene control sobre la página y desea observar algún tipo de cambio, entonces el método moderno es usar MutationObserver

Un ejemplo de su uso, observando el atributo src al cambio de un iframe

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>

Salida después de 3 segundos

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/ 

On jsFiddle

La respuesta publicada aquí como pregunta original se cerró como un duplicado de esta.

 29
Author: Xotic750,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:39

El iframe siempre mantiene la página principal, debe usar esto para detectar en qué página se encuentra en el iframe:

Código 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);
    }
 4
Author: Tarik FAMIL,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-05 09:21:05

Aquí está el método que se usa en Commerce SagePay y en Commerce Paypoint Los módulos Drupal que básicamente comparan document.location.href con el valor antiguo cargando primero su propio iframe, luego uno externo.

Así que básicamente la idea es cargar la página en blanco como un marcador de posición con su propio código JS y forma oculta. Luego el código JS padre enviará esa forma oculta donde su #action apunta al iframe externo. Una vez que ocurre el redireccionamiento / envío, el código JS que aún se está ejecutando en esa página puede rastrear sus cambios de valor document.location.href.

Aquí está el ejemplo JS usado en iframe:

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

Y aquí está JS usado en la página principal:

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

Luego, en la página de destino temporal en blanco, debe incluir el formulario que redirigirá a la página externa.

 1
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-16 15:49:08

Otras respuestas propusieron el evento load, pero se dispara después de que se cargue la nueva página en el iframe. Es posible que deba ser notificado inmediatamente después de que la URL cambie, no después de que se cargue la nueva página.

Aquí hay una solución simple de 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>

Esto rastreará con éxito los cambios en el atributo src, así como cualquier cambio de URL realizado dentro del iframe.

Probado en todos los modernos navegador.

Nota: El fragmento de código anterior solo funcionaría si el iframe tiene el mismo origen.

Hice un gist con este código también. Usted puede comprobar mi otra respuesta también. Profundiza un poco en cómo funciona esto.

 1
Author: Hristiyan Dodov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-06 14:25:15

Desde la versión 3.0 de Jquery es posible que obtenga un error

TypeError: url.indexOf no es una función

Que se puede arreglar fácilmente haciendo

$('#iframe').on('load', function() {
    alert('frame has (re)loaded ');
});
 0
Author: subharb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-18 09:58:01