Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery: how to listen to the image loaded event of one container div?

I have a container that has some images inside, I want to listen to the event of every image finish loaded.

eg)

<div id="container">
     <img src="..." />
     <img src="..." />
     <img src="..." />
     <img src="..." />
</div>

I should got 4 times of the "image loaded" event. How to do this?

like image 350
Bin Chen Avatar asked Dec 20 '11 02:12

Bin Chen


1 Answers

The only reliable way to listen to the load events of images that are in your HTML source is to specify an onload handler in the HTML:

<div id="container">
     <img onload="imageLoad()" src="..." />
     <img onload="imageLoad()" src="..." />
     <img onload="imageLoad()" src="..." />
     <img onload="imageLoad()" src="..." />
</div>

This is because you can't attach event handlers to images in your page HTML until the image tags are loaded themselves (so they are present in the DOM). Once those images tags are loaded, the source of the image is already being loaded and, if it's available quickly (like in the browser cache), it might get loaded before you can attach the event handler. Thus, at best you can't be sure it will work and at worst, it won't work. In any case, it may not be reliable.

Or, if you just want to know when all images are loaded in the page, you can use the load event for the whole document. In jQuery, you can do that with $(window).load(fn).

Or, you can attach the load events and then check to see if any of the images are already loaded and count those as loaded. I'm not sure if there's an official standard way to see if an image is already loaded or not, but I have found that if there is no width set in the HTML and there is a non-zero value for the .width attribute, then the image must be loaded because it's the loading of the image that causes the non-zero width value to get set.

Your other option is to not put the images into the HTML of your page and add them dynamically and you can assign load handlers when you create the images before you assign the .src attribute.


Testing the Issue

To explore this a little further, I built a test bed in jsFiddle: http://jsfiddle.net/jfriend00/7FjdJ/. It has four images in it and reports how many images are already loaded when $(document).ready() fires and reports how many images fire the .load() event. The results show a variation in behavior from one browser to the next.

In Chrome 15, if the images are already in the cache, I get no load events and all four are already loaded when $(document).ready() fires. The behavior appears to vary depending upon how much content there is in the page after the images.

In Safari 5, the first time I load the page, it reports 4 load events, 0 images already loaded. The second time I load the page, it reports 0 load events, 4 images already loaded.

In IE9, the images always appear to already be loaded and no load events fire, whether cached or not.

In Firefox 7, the first time I load the page, I get 0 load events and 4 images already loaded. The next time I load the page, I get 4 load events and 4 images already loaded.

Also, since this is a timing issue, it wouldn't surprise me if the behavior depends upon the size of the images and speed of loading them as slow loading images could cause load events to fire late enough to be seen. It may also depend upon how much content there is to load in the page after the images (e.g. how much work is to be done before document.ready can be fired).

So, my conclusion is that the behavior of the .load() event handler when installed after the image has started loading is inconsistent from one browser to the next and from one situation to the next, thus you cannot count on it without other code to mitigate those differences (checking to see if the images are already loaded).


There is another approach. You can install the event handlers after the DOM has loaded and when installing the event handler, you can check if the image is already loaded. Here's one way to do that:

<div id="container">
     <img src="..." />
     <img src="..." />
     <img src="..." />
     <img src="..." />
</div>

<script>
$("#container img").each(function() {
    if (this.complete) {
        // this image already loaded
        // do whatever you would do when it was loaded
    } else {
        $(this).on('load', function() {
            // image now loaded
        });
    }
}); 

Working demo: http://jsfiddle.net/jfriend00/6Cq4y/

What you will find in the demo is that if your browser cache has never seen this jsFiddle, then if will show 4 load events, but if the browser cache has already seen this jsFiddle, then it will get no load events and all the images will already be loaded by the time your javascript runs and it will see they are loaded in the if (this.complete) branch of the code.

like image 192
jfriend00 Avatar answered Sep 21 '22 02:09

jfriend00