iFrame src ubah deteksi acara?

181

Dengan asumsi saya tidak memiliki kontrol atas konten di iframe, apakah ada cara saya bisa mendeteksi perubahan src di dalamnya melalui halaman induk? Semacam beban mungkin?

Pilihan terakhir saya adalah melakukan tes interval 1 detik jika iframe src sama dengan sebelumnya, tetapi melakukan solusi hacky ini akan menyedot.

Saya menggunakan perpustakaan jQuery jika itu membantu.

Matrym
sumber
3
Apakah srcproperti akan berubah ketika tautan di iframe diklik? Saya tidak yakin tentang itu - jika saya harus menebak, apakah akan mengatakan "tidak". Ada beberapa cara untuk memonitor properti (di Firefox setidaknya AFAIK) tetapi saya tidak yakin apakah akan ada gunanya dalam kasus ini.
Pekka
Saya mencoba menerapkan sesuatu seperti ini, dan dapat mengonfirmasi bahwa srcatribut di DOM tidak berubah dalam versi terbaru FireFox atau Safari. @ Michiel jawaban di bawah ini sama baiknya dengan yang saya bisa sejauh ini.
Kaelin Colclasure

Jawaban:

201

Anda mungkin ingin menggunakan onLoadacara tersebut, seperti dalam contoh berikut:

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

Lansiran akan muncul setiap kali lokasi dalam iframe berubah. Ini bekerja di semua browser modern, tetapi mungkin tidak berfungsi di beberapa browser yang sangat lama seperti IE5 dan Opera awal. ( Sumber )

Jika iframe menampilkan halaman dalam domain induk yang sama , Anda dapat mengakses lokasi dengan contentWindow.location, seperti dalam contoh berikut:

<iframe src="/test.html" onLoad="alert(this.contentWindow.location);"></iframe>
Daniel Vassallo
sumber
13
Maksud Anda this.contentWindow.location.href
Nikolai
@Daniel Vassallo dengan asumsi Anda mengambil pendekatan ini ketika Anda ingin menangani masalah keamanan, tidak bisakah seseorang menimpa acara onLoad lalu mengubah konten iframe?
Noam Shaish
15
Ketika saya melakukannya, this.contentWindow.location.hrefsaya dapatkanPermission denied to access property 'href'
Mazatec
4
this.contentWindow.location.href tidak akan berfungsi karena Anda melakukan permintaan lintas asal. :( Semua browser membatasi itu sekarang.
Naveen
2
Koreksi: this.contentWindow.locationtersedia untuk domain lain. Bahkan this.contentWindow.location.hreftersedia untuk domain lain, tetapi hanya untuk menulis. Namun membaca this.contentWindow.location.hrefterbatas pada domain yang sama.
wadim
57

Jawaban berdasarkan JQuery <3

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

Seperti yang disebutkan oleh subharb, seperti dari JQuery 3.0 ini perlu diubah menjadi:

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

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

Michiel
sumber
2
Tidak bekerja persis seperti yang direncanakan. Ini mengaktifkan peringatan pada pemuatan halaman awal. Bergantung pada apa rencana Anda untuk kode ini (bagi saya, saya menghidupkan dialog dari halaman pada form submit) solusi ini tidak akan berfungsi.
stacigh
@ stracigh, itu benar, acara akan menyala setiap kali frame dimuat, demikian juga pertama kali di halaman awal dimuat. Jika Anda tidak ingin kode Anda terpicu saat pertama kali Anda harus entah bagaimana mendeteksi ini adalah frame load pertama Anda dan kembali.
Michiel
@FooBar, Ya itu berfungsi lintas domain, pada kenyataannya itulah yang saya gunakan untuk itu. Tetapi Anda tidak dapat mengakses halaman di iFrame dengan javascript ketika halaman itu ada di domain lain.
Michiel
ini berfungsi dan mendeteksi ketika konten dimuat, saya perlu cara untuk mendeteksi ketika src berubah. Sesuatu seperti beforeLoad (untuk mengaktifkan loader)
Andrea_86
Seperti yang ditunjukkan oleh @stacigh, itu akan mem-event sekali di halaman induk. Jika Anda mendeklarasikan penghitung di luar fungsi itu dan membacanya di dalam, Anda dapat mendeteksi perubahan setelah itu. Anda akan menambah penghitung di dalam onload handler plus have if (counter > 1) { // do something on iframe actual change }(anggap penghitung diatur ke 0 pada awal)
Alex
38

Jika Anda tidak memiliki kendali atas halaman dan ingin melihat beberapa jenis perubahan maka metode modern yang digunakan MutationObserver

Contoh penggunaannya, mengamati srcatribut berubah dariiframe

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>

Keluaran setelah 3 detik

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/ 

Di jsFiddle

Diposting jawaban di sini karena pertanyaan awal ditutup sebagai duplikat dari pertanyaan ini.

Xotic750
sumber
Bagaimana jika saya menggunakan Komponen Web dan salah satu komponen kustom saya memiliki atribut src? Saya pikir ini tidak sengaja akan mengambilnya.
Luke
Kemudian Anda mengubah opsi pada observe. Ini hanya sebuah contoh.
Xotic750
@PaulRoub menghapus tautan jsfiddle (pasti kesalahan salin / tempel) dan memasukkan kode sebagai cuplikan.
Xotic750
4
Tetapi dalam kasus saya, perubahan frame.contentDocument.URL (dari tautan di dalam bingkai) bukan src. Bisakah saya menontonnya?
httpete
Tidak yakin, lebih baik menulis pertanyaan menurut saya.
Xotic750
11

Catatan: Cuplikan hanya akan berfungsi jika iframe dengan asal yang sama.

Jawaban lain mengusulkan loadacara tersebut, tetapi muncul setelah halaman baru di iframe dimuat. Anda mungkin perlu diberi tahu segera setelah URL berubah , bukan setelah halaman baru dimuat.

Inilah solusi JavaScript sederhana:

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>

Ini akan berhasil melacak srcperubahan atribut, serta setiap perubahan URL yang dibuat dari dalam iframe itu sendiri.

Diuji di semua browser modern.

Saya membuat inti dengan kode ini juga. Anda dapat memeriksa jawaban saya yang lain juga. Ini sedikit mendalam tentang bagaimana ini bekerja.

dodov
sumber
6

Iframe selalu menyimpan halaman induk, Anda harus menggunakan ini untuk mendeteksi di halaman mana Anda berada di iframe:

Kode 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);
    }
Tarik FAMIL
sumber
2

Karena versi 3.0 dari Jquery Anda mungkin mendapatkan kesalahan

TypeError: url.indexOf bukan fungsi

Yang dapat dengan mudah diperbaiki dengan melakukan

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

Berikut adalah metode yang digunakan dalam Commerce SagePay dan modul Commerce Paypoint Drupal yang pada dasarnya membandingkan document.location.hrefdengan nilai lama dengan terlebih dahulu memuat iframe sendiri, kemudian eksternal.

Jadi pada dasarnya idenya adalah memuat halaman kosong sebagai pengganti dengan kode JS dan bentuk tersembunyi. Kemudian kode induk JS akan mengirimkan formulir tersembunyi di mana #actionmenunjuk ke iframe eksternal. Setelah pengalihan / pengiriman terjadi, kode JS yang masih berjalan di halaman itu dapat melacak document.location.hrefperubahan nilai Anda .

Berikut ini contoh JS yang digunakan di iframe:

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

Dan di sini JS digunakan di halaman induk:

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

Kemudian di halaman pendaratan sementara yang kosong, Anda harus memasukkan formulir yang akan dialihkan ke halaman eksternal.

kenorb
sumber
Ini mungkin peretasan tetapi overhead-nya jauh lebih kecil dari pengamat mutasi. Ketika digunakan dalam satu aplikasi halaman, berhati-hatilah untuk tidak membuat referensi yang akan mencegah sisa dari peretasan ini dikumpulkan dari sampah.
Jeff