iFrame src altera a detecção de events?

Assumindo que não tenho controle sobre o conteúdo no iframe, existe alguma maneira de detectar uma alteração src na página principal? Algum tipo de onload talvez?

Meu último recurso é fazer um teste de intervalo de 1 segundo se o iframe src é o mesmo que era antes, mas fazer essa solução hacky seria uma droga.

Estou usando a biblioteca jQuery se isso ajudar.

Você pode querer usar o evento onLoad , como no exemplo a seguir:

  

O alerta será exibido sempre que o local dentro do iframe for alterado. Ele funciona em todos os navegadores modernos, mas pode não funcionar em alguns navegadores muito antigos, como o IE5 e o Early Opera. ( Fonte )

Se o iframe estiver mostrando uma página no mesmo domínio do pai , você poderá acessar o local com contentWindow.location , como no exemplo a seguir:

  

Resposta baseada em JQuery <3

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

Conforme mencionado pelo subharb, como no JQuery 3.0, isso precisa ser alterado para:

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

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

Se você não tem controle sobre a página e deseja observar algum tipo de mudança, então o método moderno é usar o MutationObserver

Um exemplo de seu uso, observando o atributo src para alterar um 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); 
  

O iframe sempre mantém a página pai, você deve usar isso para detectar em qual página você está no iframe:

Código HTML:

  

Js:

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

Aqui está o método que é usado no Commerce SagePay e nos módulos Commerce Paypoint Drupal que basicamente compara document.location.href com o valor antigo carregando primeiro seu próprio iframe, depois o externo.

Então, basicamente, a idéia é carregar a página em branco como um espaço reservado com seu próprio código JS e forma oculta. Em seguida, o código JS pai enviará o formulário oculto onde o #action aponta para o iframe externo. Quando o redirecionamento / envio acontece, o código JS que ainda está sendo executado nessa página pode rastrear suas alterações no valor document.location.href .

Aqui está o exemplo JS usado no iframe:

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

E aqui está o JS usado na página pai:

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

Em seguida, na página de destino em branco temporária, você precisa include o formulário que redirectá para a página externa.

Outras respostas propuseram o evento load , mas ele é acionado depois que a nova página no iframe é carregada. Você pode precisar ser notificado imediatamente após a alteração do URL , não depois que a nova página for carregada.

Aqui está uma solução simples 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); }); 
  

Desde a versão 3.0 do Jquery, você pode receber um erro

TypeError: url.indexOf não é uma function

Que pode ser facilmente corrigido fazendo

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