Why is iframe.contentWindow == null?

2019-01-11 08:46发布

I use the following code to dynamically create an iframe.

var iframe_jquery = $("<iframe>")
    .addClass("foo")
    .appendTo(container); // container is a jQuery object containing a <div> which already exists

Then, I want to access its contentWindow, but it's null:

var iframe = iframe_jquery.get(0);
if (iframe){ // iFrame exists
    console.log(iframe.contentWindow); // Prints "null"
    var doc = iframe.contentWindow.document; // NullpointerException
}

So I thought: "Maybe the iframe isn't ready yet?" So I tried:

iframe_jquery.ready(function(){
    var iframe = iframe_jquery.get(0);
    console.log(iframe.contentWindow); // Prints "null"
    var doc = iframe.contentWindow.document; // NullpointerException
});

Same result.

What's wrong?

6条回答
甜甜的少女心
2楼-- · 2019-01-11 09:08

I had a similar situation where contentWindow would be null (about 50% of the time immediately after document was loaded), but I wanted to set the iframe's src via element.contentWindow.location.replace.

To solve it, I did a loop that waits for contentWindow to not be null... like so:

function setIframeLocation(element, value) {
    if (element.contentWindow !== null) {
        element.contentWindow.location.replace(value);
    }
    else {
        setTimeout(setIframeLocation.bind(this, element, value), 100); 
    }
}

setIframeLocation(element, 'http://google.com');
查看更多
叛逆
3楼-- · 2019-01-11 09:11

Bookmarklet version

Just out of curiosity I thought I'd put this together. Remembering that iframes and load events don't play well together on different browsers (mainly older, falling apart, should-be-dead browsers)... plus not being entirely sure how jQuery gets around this problem... my brain decided that this would be better supported (whether it is or not is neither here nor there):

$(function(){
  /// bind a listener for the bespoke iframeload event
  $(window).bind('iframeload', function(){
    /// access the contents of the iframe using jQuery notation
    iframe.show().contents().find('body').html('hello');
  });
  /// create your iframe
  var iframe = $('<iframe />')
        /// by forcing our iframe to evaluate javascript in the path, we know when it's ready
        .attr('src', 'javascript:(function(){try{p=window.parent;p.jQuery(p).trigger(\'iframeload\');}catch(ee){};})();')
        /// insert the iframe into the live DOM
        .appendTo('body');
});

The reason for taking this approach is that it is normally far better to trigger your load event from inside the iframe itself. But this means having a proper document loaded in to the iframe, so for dynamic iframes this is a little tedious. This is kind of a mixture between having a document loaded, and not.

The above works on everything I have tested so far - and yes you are correct - it is a little ridiculous, non-future-proof and propably other things that have negative connotations ;)

One positive thing I'll say about this post is that introduces the use of .contents() to access the document of the iframe, which is at least a little bit useful...

查看更多
放我归山
4楼-- · 2019-01-11 09:12

The problem is that your <iframe> won't be "real" until it's really added to the actual DOM for the page. Here is a fiddle to demonstrate..

查看更多
SAY GOODBYE
5楼-- · 2019-01-11 09:16

You can also make a function that will be executed when the iframe has finished loading by setting it's onload attribute.

查看更多
萌系小妹纸
6楼-- · 2019-01-11 09:20

Depending on the browser, accessing the document or an <iframe> may vary.

Here is an example of how to handle it:

if (iframe.contentDocument) // FF Chrome
  doc = iframe.contentDocument;
else if ( iframe.contentWindow ) // IE
  doc = iframe.contentWindow.document;
查看更多
家丑人穷心不美
7楼-- · 2019-01-11 09:26

I had this problem last week while playing with iFrames (building an rtf editor), and yeah it's not ready yet.

I thought if I put it in a .ready() it would work, but .ready() is when the DOM is ready, not when the iFrame has loaded its contents, so I ended up wrapping my code with jQuery .load().

So try this:

$(function () {  
    $("#myiframe").load(function () {                        
        frames["myframe"].document.body.innerHTML = htmlValue;
    });
}); 

Hope this helps

查看更多
登录 后发表回答