iFrame src change event detection?

前端 未结 7 1324
夕颜
夕颜 2020-11-22 08:02

Assuming I have no control over the content in the iframe, is there any way that I can detect a src change in it via the parent page? Some sort of onload maybe?

My l

相关标签:
7条回答
  • 2020-11-22 08:24

    If you have no control over the page and wish to watch for some kind of change then the modern method is to use MutationObserver

    An example of its use, watching for the src attribute to change of an 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>

    Output after 3 seconds

    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

    Posted answer here as original question was closed as a duplicate of this one.

    0 讨论(0)
  • 2020-11-22 08:31

    The iframe always keeps the parent page, you should use this to detect in which page you are in the iframe:

    Html code:

    <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);
        }
    
    0 讨论(0)
  • 2020-11-22 08:35

    Here is the method which is used in Commerce SagePay and in Commerce Paypoint Drupal modules which basically compares document.location.href with the old value by first loading its own iframe, then external one.

    So basically the idea is to load the blank page as a placeholder with its own JS code and hidden form. Then parent JS code will submit that hidden form where its #action points to the external iframe. Once the redirect/submit happens, the JS code which still running on that page can track your document.location.href value changes.

    Here is example JS used in iframe:

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

    And here is JS used in parent page:

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

    Then in temporary blank landing page you need to include the form which will redirect to the external page.

    0 讨论(0)
  • 2020-11-22 08:39

    Note: The snippet would only work if the iframe is with the same origin.

    Other answers proposed the load event, but it fires after the new page in the iframe is loaded. You might need to be notified immediately after the URL changes, not after the new page is loaded.

    Here's a plain JavaScript solution:

    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>

    This will successfully track the src attribute changes, as well as any URL changes made from within the iframe itself.

    Tested in all modern browsers.

    I made a gist with this code as well. You can check my other answer too. It goes a bit in-depth into how this works.

    0 讨论(0)
  • 2020-11-22 08:40

    Answer based on JQuery < 3

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

    As mentioned by subharb, as from JQuery 3.0 this needs to be changed to:

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

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

    0 讨论(0)
  • 2020-11-22 08:47

    Since version 3.0 of Jquery you might get an error

    TypeError: url.indexOf is not a function

    Which can be easily fix by doing

    $('#iframe').on('load', function() {
        alert('frame has (re)loaded ');
    });
    
    0 讨论(0)
提交回复
热议问题