iFrame src виявлення подій зміни?


181

Якщо припустити, що я не контролюю вміст у iframe, чи можна виявити зміни src в ньому через батьківську сторінку? Якась навантаження, можливо?

Моє останнє рішення - зробити тест на 1 секунду інтервалу, якщо iframe src такий же, як був раніше, але це хакі розв’язання буде недостойним.

Я використовую бібліотеку jQuery, якщо це допомагає.


3
Чи srcзміниться властивість при натисканні на посилання в iframe? Я не впевнений у цьому - якби мені довелося здогадуватися, чи сказав би "ні". Там є способи властивостей монітора (в Firefox по крайней мере , AFAIK) , але я не впевнений , чи буде якесь - або використання в даному випадку.
Pekka

Я намагаюся реалізувати щось подібне і можу підтвердити, що srcатрибут у DOM не змінюється в останніх версіях FireFox або Safari. @ Відповідь Міхеля нижче, настільки ж хороша, як мені вдалося дійти до цих пір.
Каелін розбір

Відповіді:


201

Ви можете використовувати onLoadподію, як у наступному прикладі:

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

Повідомлення з’явиться щоразу, коли розташування в кадрі зміниться. Він працює у всіх сучасних браузерах, але може не працювати в таких дуже старих браузерах, як IE5 та рання Opera. ( Джерело )

Якщо в кадрі iframe відображається сторінка в тому ж домені батьків , ви зможете отримати доступ до місця розташування contentWindow.location, як у наступному прикладі:

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

13
Ви маєте на увазі this.contentWindow.location.href
Микола

@Daniel Vassallo припускаючи, що ти приймеш цей підхід, коли ти хочеш вирішити питання безпеки, чи не може хтось просто перекрити подію onLoad, а потім змінити вміст iframe?
Ноам Шаїш

15
Коли я this.contentWindow.location.hrefдістаюсьPermission denied to access property 'href'
Mazatec

4
this.contentWindow.location.href звичайно не працює, тому що ви робите запит на поперечне походження. :( Усі браузери обмежують це зараз.
Naveen

2
Виправлення: this.contentWindow.locationдоступно для інших доменів. Навіть this.contentWindow.location.hrefдоступний для інших доменів, але лише для написання. Однак читання this.contentWindow.location.hrefобмежується одним і тим же доменом.
вадим

57

Відповідь на основі JQuery <3

$('#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


3
Не працює точно так, як планувалося. Він запускає попередження про початкове завантаження сторінки. Залежно від того, які ваші плани щодо цього коду (для мене я анімую діалогове вікно зі сторінки при подачі форми), це рішення не працюватиме.
stacigh

@stracigh, це правильно, подія запускається кожного разу, коли кадр завантажується, а також вперше при початковому завантаженні сторінки. Якщо ви не хочете, щоб ваш код був запущений в перший раз, ви повинні якось виявити, це ваше перше завантаження кадру і повернення.
Міхель

@FooBar, так, це працює міждоменним, адже саме для цього я і використовував його. Але ви не можете отримати доступ до сторінки в iFrame з JavaScript, коли ця сторінка знаходиться на іншому домені.
Міхель

це працює і виявляє, коли вміст завантажується, мені потрібен спосіб виявити, коли src змінюється. Щось на кшталт beforeLoad (щоб активувати навантажувач)
Andrea_86

Як вказує @stacigh, він запустить подію один раз на завантаженні батьківської сторінки. Якщо ви оголосили лічильник поза цією функцією і прочитали його всередині, ви можете виявити зміни після цього. Ви зробили б лічильник приросту всередині обробника завантаження плюс мати if (counter > 1) { // do something on iframe actual change }(якщо лічильник встановлений на 0 на початку)
Алекс

38

Якщо ви не маєте контролю над сторінкою і хочете спостерігати за якимись змінами, тоді слід використовувати сучасний метод 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/ 

На jsFiddle

Опублікована відповідь тут, оскільки оригінальне запитання було закрито як дублікат цього.


Що робити, якщо я використовую веб-компоненти, і один із моїх спеціальних компонентів має атрибут src? Я думаю, що це випадково підхопить його.
Лука

Потім ви зміните параметри на observe. Це лише приклад.
Xotic750

@PaulRoub видалив посилання jsfiddle (повинно бути помилка копіювання / вставки) і включив код у фрагмент.
Xotic750

4
Але в моєму випадку frame.contentDocument.URL змінюється (із посилань всередині кадру) не src. Чи можу я це спостерігати?
httpste

Не впевнений, найкраще написати запитання, яке я думаю.
Xotic750

11

Примітка . Фрагмент працює лише в тому випадку, якщо кадр iframe має однакове походження.

Інші відповіді пропонували 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.

Тестується у всіх сучасних браузерах.

Я також створив суть цього коду. Ви можете також перевірити мою іншу відповідь . Це трохи поглиблюється, як це працює.


6

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

2

Починаючи з версії 3.0 Jquery, ви можете отримати помилку

TypeError: url.indexOf не є функцією

Що можна легко виправити, зробивши

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

1

Ось метод, який використовується в 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);

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


Це може бути хак, але накладні витрати значно менше, ніж спостерігач за мутацією. Використовуючи програму на одній сторінці, слід пам’ятати, що не створювати жодних посилань, які не дозволять залишкам цього хака збирати сміття.
Джефф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.