关于javascript:iFrame src更改事件检测?

iFrame src change event detection?

假设我无法控制iframe中的内容,是否有任何方法可以通过父页面检测到其中的src更改? 可能是某种负载?

我的最后一招是如果iframe src与以前的相同,则进行1秒间隔测试,但是这样做会导致问题。

如果有帮助,我正在使用jQuery库。


您可能要使用onLoad事件,如以下示例所示:

1
<iframe src="http://www.google.com/" onLoad=";"></iframe>

只要iframe中的位置发生更改,警报就会弹出。它适用于所有现代浏览器,但可能不适用于某些较旧的浏览器,例如IE5和早期的Opera。 (资源)

如果iframe在父级的同一个域中显示页面,则可以使用contentWindow.location访问该位置,如以下示例所示:

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


基于JQuery <3的答案

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

如subharb所述,从JQuery 3.0开始,需要将其更改为:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
1
<iframe src="http://www.google.com"></iframe>

3秒后输出

1
2
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上

由于原始问题已作为此问题的重复部分被关闭,因此在此处发布了答案。


注意:仅当iframe的来源相同时,该代码段才有效。

其他答案提出了load事件,但在加载iframe中的新页面后将触发该事件。 URL更改后可能需要立即得到通知,而不是在新页面加载后得到通知。

这是一个简单的JavaScript解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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);
});
1
<iframe id="mainframe" src=""></iframe>

这将成功跟踪src属性的更改以及从iframe本身进行的所有URL更改。

在所有现代浏览器中测试。

我也用此代码做了要点。您也可以查看我的其他答案。它将对它的工作原理进行一些深入的介绍。


iframe始终保留父页面,您应该使用它来检测您在iframe中处于哪个页面:

HTML代码:

1
<iframe id="iframe" frameborder="0" scrolling="no" onload="resizeIframe(this)" width="100%" src="www.google.com"></iframe>

Js:

1
2
3
    function resizeIframe(obj) {
        alert(obj.contentWindow.location.pathname);
    }

由于Jquery 3.0版,您可能会收到错误消息

TypeError: url.indexOf is not a function

可以很容易地通过修复来解决

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

这是在Commerce SagePay和Commerce Paypoint Drupal模块中使用的方法,该方法通过首先加载自己的iframe,然后是外部iframe,将document.location.href与旧值进行比较。

因此,基本上,这个想法是使用自己的JS代码和隐藏形式将空白页作为占位符加载。然后,父JS代码将提交该隐藏表单,该表单的#action指向外部iframe。一旦发生重定向/提交,仍在该页面上运行的JS代码可以跟踪您的document.location.href值更改。

这是iframe中使用的示例JS:

1
2
3
4
5
6
7
8
9
10
;(function($) {
  Drupal.behaviors.commercePayPointIFrame = {
    attach: function (context, settings) {
      if (top.location != location) {
        $('html').hide();
        top.location.href = document.location.href;
     }
    }
  }
})(jQuery);

这是父页面中使用的JS:

1
2
3
4
5
6
7
8
9
10
11
12
;(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);

然后,在临时空白登录页面中,您需要包括将重定向到外部页面的表格。