iFrame src değişiklik olayı algılama?


181

İç çerçevedeki içerik üzerinde hiçbir denetime sahip olmadığımı varsayarsak, üst sayfa aracılığıyla bir src değişikliğini tespit edebilmemin herhangi bir yolu var mı? Belki bir çeşit yük?

Son çare, iframe src'nin öncekiyle aynı olması durumunda 1 saniyelik bir aralık testi yapmaktır, ancak bu hacky çözümünü yapmak berbat olur.

Eğer yardımcı olursa jQuery kütüphanesini kullanıyorum.


3
İframe'deki srcbir bağlantı tıklandığında özellik değişecek mi? Bundan emin değilim - tahmin etmek zorunda kalsaydım, "hayır" derse. Orada olan (en afaik de Firefox'ta) monitör özelliklerine yolları ama emin bu durumda herhangi bir kullanım olup olmayacağını değilim.
Pekka

Böyle bir şey uygulamak çalışıyorum ve teyit edebiliriz srcDOM öznitelik yok değil FireFox veya Safari ya en son sürümlerinde değiştirin. @ Michiel'in aşağıdaki cevabı şimdiye kadar elde edebildiğim kadar iyi.
Kaelin Colclasure

Yanıtlar:


201

onLoadAşağıdaki örnekte olduğu gibi etkinliği kullanmak isteyebilirsiniz :

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

İframe içindeki konum her değiştiğinde uyarı açılır. Tüm modern tarayıcılarda çalışır, ancak IE5 ve erken Opera gibi bazı eski tarayıcılarda çalışmayabilir. ( Kaynak )

İframe, üst öğenin aynı alan adında bir sayfa gösteriyorsa , konuma contentWindow.locationaşağıdaki örnekte olduğu gibi erişebilirsiniz :

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

13
Bunu kastediyorsun.contentWindow.location.href
Nikolai

@Daniel Vassallo, güvenlik sorununu ele almak istediğinizde bu yaklaşımı aldığınızı varsayarsak, birisi onLoad olayını geçersiz kılar ve iframe içeriğini değiştiremez mi?
Noam Shaish

15
Ne zaman this.contentWindow.location.hrefalırımPermission denied to access property 'href'
Mazatec

4
this.contentWindow.location.href alışkanlık bcoz alışkanlık çapraz bir istek yapıyoruz. :( Tüm tarayıcılar bunu şimdi kısıtlıyor.
Naveen

2
Düzeltme: this.contentWindow.locationdiğer alanlar için kullanılabilir. this.contentWindow.location.hrefDiğer etki alanları için bile kullanılabilir, ancak yalnızca yazma için kullanılabilir. Ancak, okuma this.contentWindow.location.hrefaynı alanla sınırlıdır.
Wadim

57

Yanıt temelli JQuery <3

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

Subharb tarafından belirtildiği gibi, JQuery 3.0'dan itibaren bunun şu şekilde değiştirilmesi gerekir:

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

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


3
Tam olarak planlandığı gibi çalışmaz. İlk sayfa yüklemesinde uyarıyı tetikler. Bu kod için planlarınızın ne olduğuna bağlı olarak (benim için iletişim kutusunu form gönderme sayfasındaki animasyonu yapıyorum) bu çözüm çalışmaz.
stacigh

@stracigh, doğru, çerçeve her yüklendiğinde olay tetiklenir, bu nedenle ilk sayfa yüklemesinde ilk kez de tetiklenir. Kodunuzun ilk kez tetiklenmesini istemiyorsanız, bir şekilde bunun ilk kare yükünüz ve dönüşünüz olduğunu algılamanız gerekir.
Michiel

@FooBar, Evet etki alanları arası çalışıyor, aslında bunun için kullandım. Ancak bu sayfa başka bir etki alanındayken iFrame'deki sayfaya javascript ile erişemezsiniz.
Michiel

Bu çalışır ve içerik yüklendiğinde tespit, ben src değiştiğinde tespit etmek için bir yol gerekir. Daha önce gibi bir şeyYük (yükleyiciyi etkinleştirmek için)
Andrea_86

@Stacigh tarafından belirtildiği gibi, etkinliği ana sayfa yüklemesinde bir kez tetikler. Bu işlevin dışında bir sayaç bildirir ve içeride okursanız, bundan sonraki değişiklikleri tespit edebilirsiniz. Sayacı onload işleyicisinin içinde artırabilirsiniz if (counter > 1) { // do something on iframe actual change }(sayacın başlangıçta 0 olarak ayarlandığını varsayarak)
Alex

38

Sayfa üzerinde kontrolünüz yoksa ve bir çeşit değişikliği izlemek istiyorsanız, modern yöntem MutationObserver

Kullanımının bir örneği src, biriframe

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 saniye sonra çıktı

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

Orijinal soru olarak gönderilen cevap bu bir kopyası olarak kapatıldı.


Web Bileşenleri kullanıyorsam ve özel bileşenlerimden birinin src özelliği varsa ne olur? Sanırım bu yanlışlıkla onu alacaktı.
Luke

Sonra seçenekleri değiştirirsiniz observe. Bu sadece bir örnek.
Xotic750

@PaulRoub jsfiddle bağlantısını kaldırdı (kopyala / yapıştır hatası olmalı) ve kodu pasaj olarak ekledi.
Xotic750

4
Ama benim durumumda, frame.contentDocument.URL değişiyor (çerçeve içindeki bağlantılardan) src değil. Bunu izleyebilir miyim?
httpete

Emin değilim, en iyisi bence bir soru yazmak.
Xotic750

11

Not: Parçacık yalnızca iframe aynı orijinale sahipse çalışır.

Diğer cevaplar teklif edilen loadolay, ama bu ateşler sonra iframe'de yeni sayfa yüklenir. URL değiştikten hemen sonra, yeni sayfa yüklendikten sonra değil, bilgilendirilmeniz gerekebilir .

İşte sade bir JavaScript çözümü:

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>

Bu, başarılı bir şekilde src özellik değişikliklerinin yanı sıra iframe'in içinden yapılan URL değişikliklerini de .

Tüm modern tarayıcılarda test edilmiştir.

Ben de bu kod ile bir özledim . Diğer cevabımı da kontrol edebilirsiniz . Bunun nasıl işlediğine dair biraz derinlemesine ilerliyor.


6

İframe her zaman üst sayfayı tutar, iframe'de hangi sayfada olduğunuzu tespit etmek için bunu kullanmalısınız:

HTML Kodu:

<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

Jquery 3.0 sürümünden beri bir hata alabilirsiniz

TypeError: url.indexOf bir işlev değil

Hangi yaparak kolayca düzeltilebilir

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

1

Burada kullanılan yöntemdir Ticaret SagePay ve Ticaret Paypoint temelde karşılaştırır Drupal modüllerin document.location.hrefilk yükleme ile eski değerle sonra kendi iframe harici bir.

Temel olarak fikir, boş sayfayı kendi JS kodu ve gizli formu ile bir yer tutucu olarak yüklemek. Daha sonra üst JS kodu, gizli formun #actionişaret edildiği gizli formu gönderir . Yönlendirme / gönderme işlemi gerçekleştikten sonra, o sayfada hala çalışan JS kodu document.location.hrefdeğer değişikliklerinizi izleyebilir .

İşte iframe'de kullanılan örnek JS:

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

Ve üst sayfada kullanılan 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);

Daha sonra geçici boş açılış sayfasına harici sayfaya yönlendirilecek formu eklemeniz gerekir.


Bu bir saldırı olabilir, ancak ek yük mutasyon gözlemcisinden önemli ölçüde daha azdır. Tek sayfalık bir uygulamada kullanıldığında, bu hackten arta kalanların çöp toplanmasını önleyecek referanslar oluşturmamaya dikkat edin.
Jeff
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.