обнаружение событий изменения iframe src?


предполагая, что у меня нет контроля над содержимым в iframe, есть ли способ обнаружить изменение src в нем через родительскую страницу? Может быть, какая-то нагрузка?

мое последнее средство-сделать тест с интервалом в 1 секунду, если iframe src такой же, как и раньше, но делать это хакерское решение будет сосать.

Я использую библиотеку jQuery, если это помогает.

7 145

7 ответов:

вы можете использовать onLoad событие, как в следующем примере:

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

предупреждение будет всплывать всякий раз, когда местоположение в iframe изменяется. Он работает во всех современных браузерах, но может не работать в некоторых очень старых браузерах, таких как IE5 и ранняя Опера. (источник)

если iframe показывает страницу в том же домене родительского, вы сможете получить доступ к локации с contentWindow.location, как в следующем пример:

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

ответ на основе JQuery

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

Как упоминалось subharb, начиная с JQuery 3.0 это должно быть изменено на:

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

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

если у вас нет контроля над страницей и вы хотите посмотреть на какие-то изменения, то современный метод должен использовать MutationObserver

пример его использования, наблюдая за src атрибут для изменения 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>

выход через 3 секунды

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

опубликованный ответ здесь, поскольку исходный вопрос был закрыт как дубликат этого один.

iframe всегда сохраняет родительскую страницу, вы должны использовать это, чтобы определить, на какой странице вы находитесь в iframe:

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

вот метод, который используется в Commerce SagePay и Commerce Paypoint Drupal модули, которые в основном сравнивает document.location.href со старым значением, сначала загрузив свой собственный iframe, а затем внешний.

таким образом, в основном идея состоит в том, чтобы загрузить пустую страницу в качестве заполнителя с собственным кодом JS и скрытой формой. Затем Родительский код JS отправит эту скрытую форму, где его #action указывает на внешний iframe. Как только произойдет перенаправление / отправка, JS-код, который все еще работает на этой странице, может отслеживать ваш document.location.href изменения стоимости.

вот пример JS, используемый в iframe:

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

и вот JS используется в родительской странице:

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

затем во временную пустую целевую страницу нужно включить форму, которая будет перенаправлять на внешнюю страницу.

другие ответы предложили load событие, но она горит после загружается новая страница в iframe. Возможно, Вам потребуется уведомление сразу после изменения URL, не после загрузки новой страницы.

вот простое решение 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>

это будет успешно отслеживать src изменения атрибутов, а также любые изменения URL, сделанные из iframe себя.

проверен во всех современных браузерах.

Примечание: приведенный выше фрагмент будет работать только в том случае, если iframe имеет тот же источник.

Я суть С этим кодом, а также. Вы можете проверить мой другой ответ тоже. Это идет немного углубленно в то, как это работает.

начиная с версии 3.0 Jquery вы можете получить ошибку

TypeError: url.помощи indexOf-это не функция

который можно легко исправить, сделав

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