iFrame src เปลี่ยนการตรวจจับเหตุการณ์?


181

สมมติว่าฉันไม่สามารถควบคุมเนื้อหาใน iframe มีวิธีใดบ้างที่ฉันสามารถตรวจพบการเปลี่ยนแปลง src ผ่านทางหน้าหลัก บางประเภทของการโหลดอาจจะ?

ทางเลือกสุดท้ายของฉันคือการทำการทดสอบช่วงเวลา 1 วินาทีหาก ​​iframe src เหมือนกันกับที่เคยเป็นมาก่อน แต่การทำโซลูชันแฮ็คนี้จะดูด

ฉันใช้ไลบรารี jQuery ถ้ามันช่วยได้


3
จะsrcมีการเปลี่ยนแปลงสถานที่ให้บริการเมื่อมีการเชื่อมโยงใน iframe มีการคลิก? ฉันไม่แน่ใจเกี่ยวกับเรื่องนี้ - ถ้าฉันต้องเดาถ้าจะพูดว่า "ไม่" มีมีวิธีการที่จะคุณสมบัติจอแสดงผล (ใน Firefox ที่ AFAIK น้อย) แต่ผมไม่แน่ใจว่ามันจะเป็นของใช้ใด ๆ ในกรณีนี้
Pekka

ฉันกำลังพยายามใช้งานสิ่งนี้และสามารถยืนยันได้ว่าsrcแอตทริบิวต์ใน DOM จะไม่เปลี่ยนแปลงใน FireFox หรือ Safari เวอร์ชันล่าสุด @ คำตอบของมิเชลด้านล่างนั้นดีเท่าที่ฉันสามารถทำได้
Kaelin Colclasure

คำตอบ:


201

คุณอาจต้องการใช้onLoadเหตุการณ์ดังในตัวอย่างต่อไปนี้:

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

การแจ้งเตือนจะปรากฏขึ้นทุกครั้งที่มีการเปลี่ยนตำแหน่งภายใน iframe ใช้งานได้กับเบราว์เซอร์ที่ทันสมัยทั้งหมด แต่อาจไม่ทำงานในเบราว์เซอร์รุ่นเก่าบางรุ่นเช่น IE5 และ Opera รุ่นเก่า ( ที่มา )

หาก iframe แสดงหน้าภายในโดเมนเดียวกันของพาเรนต์คุณจะสามารถเข้าถึงตำแหน่งด้วยcontentWindow.locationดังตัวอย่างต่อไปนี้:

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

13
คุณหมายถึงสิ่งนี้ contententindows.location.href
นิโคไล

@Daniel Vassallo สมมติว่าคุณรับ aproach นี้เมื่อคุณต้องการจัดการกับปัญหาด้านความปลอดภัยไม่สามารถมีคนแทนที่เหตุการณ์ onLoad แล้วเปลี่ยนเนื้อหา iframe หรือไม่
Noam Shaish

15
เมื่อฉันจะthis.contentWindow.location.hrefได้รับPermission denied to access property 'href'
Mazatec

4
this.contentWindow.location.href จะไม่ทำงาน bcoz ที่คุณกำลังทำคำขอข้ามแหล่งกำเนิด :( เบราว์เซอร์ทั้งหมด จำกัด ไว้ในตอนนี้
Naveen

2
การแก้ไข: this.contentWindow.locationพร้อมใช้งานสำหรับโดเมนอื่น แม้this.contentWindow.location.hrefจะมีให้สำหรับโดเมนอื่น ๆ แต่สำหรับการเขียนเท่านั้น อย่างไรก็ตามการอ่านthis.contentWindow.location.hrefนั้น จำกัด ไว้ที่โดเมนเดียวกัน
wadim

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 ที่ถูกต้องเหตุการณ์จะเริ่มทำงานทุกครั้งที่มีการโหลดเฟรมดังนั้นจึงเป็นครั้งแรกที่การโหลดหน้าเริ่มต้น หากคุณไม่ต้องการให้รหัสถูกทริกเกอร์ในครั้งแรกคุณจะต้องตรวจพบว่านี่เป็นการโหลดเฟรมครั้งแรกและส่งคืน
Michiel

@FooBar ใช่ทำงานข้ามโดเมนในความเป็นจริงนั่นคือสิ่งที่ฉันใช้มัน แต่คุณไม่สามารถ acces หน้าใน iFrame ด้วย javascript เมื่อหน้านั้นอยู่ในโดเมนอื่น
Michiel

งานนี้และตรวจพบเมื่อเนื้อหาโหลดฉันต้องการวิธีการตรวจสอบเมื่อ src ในการเปลี่ยนแปลง บางอย่างเช่น beforeLoad (เพื่อเปิดใช้งานตัวโหลด)
Andrea_86

ตามที่ระบุโดย @stacigh มันจะเริ่มต้นเหตุการณ์เมื่อโหลดหน้าเว็บระดับบน หากคุณประกาศตัวนับนอกฟังก์ชั่นนั้นและอ่านข้างในคุณสามารถตรวจจับการเปลี่ยนแปลงหลังจากนั้น คุณต้องการเพิ่มตัวนับภายใน onload handler plus have if (counter > 1) { // do something on iframe actual change }(สมมติว่าตัวนับถูกตั้งค่าเป็น 0 เมื่อเริ่มต้น)
Alex

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

โพสต์คำตอบที่นี่เนื่องจากคำถามเดิมถูกปิดเป็นซ้ำกับคำถามนี้


จะเกิดอะไรขึ้นถ้าฉันใช้ Web Components และองค์ประกอบที่กำหนดเองของฉันมีแอตทริบิวต์ src ฉันคิดว่านี่จะตั้งใจหยิบมันขึ้นมา
ลูกา

observeแล้วคุณจะเปลี่ยนแปลงตัวเลือกบน นี่เป็นเพียงตัวอย่าง
Xotic750

@PaulRoub ลบลิงก์ jsfiddle (ต้องเป็นข้อผิดพลาดในการคัดลอก / วาง) และรวมรหัสเป็นตัวอย่าง
Xotic750

4
แต่ในกรณีของฉัน frame.contentDocument.URL จะเปลี่ยน (จากลิงก์ภายในเฟรม) ไม่ใช่ src ฉันสามารถดูได้ไหม
httpete

ไม่แน่ใจที่ดีที่สุดที่จะเขียนคำถามที่ฉันคิดว่า
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 modules ซึ่งโดยทั่วไปจะเปรียบเทียบ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);

จากนั้นในหน้า Landing Page ว่างคุณต้องรวมฟอร์มซึ่งจะเปลี่ยนเส้นทางไปยังหน้าภายนอก


นี่อาจเป็นการแฮก แต่ค่าใช้จ่ายจะน้อยกว่าผู้สังเกตการณ์การกลายพันธุ์ เมื่อใช้ในแอปพลิเคชันหน้าเดียวโปรดระวังที่จะไม่สร้างการอ้างอิงใด ๆ ที่จะป้องกันไม่ให้ของเหลือจากการแฮ็คนี้ถูกเก็บขยะ
เจฟฟ์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.