Javascript - execute after all images have loaded

前端 未结 9 1338
陌清茗
陌清茗 2020-12-01 05:53

Having read other people\'s questions I thought

window.onload=...

would answer my question. I have tried this but it executes the code the

相关标签:
9条回答
  • 2020-12-01 06:01
     <title>Pre Loading...</title>
     </head>
    
     <style type="text/css" media="screen"> html, body{ margin:0;
     padding:0; overflow:auto; }
     #loading{ position:fixed; width:100%; height:100%; position:absolute; z-index:1; ackground:white url(loader.gif) no-repeat center; }**
     </style>
    
     <script> function loaded(){
     document.getElementById("loading").style.visibility = "hidden"; }
     </script>
    
     <body onload="loaded();"> <div id="loading"></div>
    
     <img id="img" src="avatar8.jpg" title="AVATAR" alt="Picture of Avatar
     movie" />
    
    
     </body>
    
    0 讨论(0)
  • 2020-12-01 06:03

    Want a one-liner?

    Promise.all(Array.from(document.images).filter(img => !img.complete).map(img => new Promise(resolve => { img.onload = img.onerror = resolve; }))).then(() => {
        console.log('images finished loading');
    });
    

    Pretty backwards-compatible, works even in Firefox 52 and Chrome 49 (Windows XP era). Not in IE11, though.

    Replace document.images with e.g. document.querySelectorAll(...) if you want to narrow the image list.

    It uses onload and onerror for brevity. This might conflict with other code on the page if these handlers of the img elements are also set elsewhere (unlikely, but anyway). If you're not sure that your page doesn't use them and want to be safe, replace the part img.onload = img.onerror = resolve; with a lengthier one: img.addEventListener('load', resolve); img.addEventListener('error', resolve);.

    It also doesn't test whether all images have loaded successfully (that there are no broken images). If you need this, here's some more advanced code:

    Promise.all(Array.from(document.images).map(img => {
        if (img.complete)
            return Promise.resolve(img.naturalHeight !== 0);
        return new Promise(resolve => {
            img.addEventListener('load', () => resolve(true));
            img.addEventListener('error', () => resolve(false));
        });
    })).then(results => {
        if (results.every(res => res))
            console.log('all images loaded successfully');
        else
            console.log('some images failed to load, all finished loading');
    });
    

    It waits until all images are either loaded or failed to load.

    If you want to fail early, with the first broken image:

    Promise.all(Array.from(document.images).map(img => {
        if (img.complete)
            if (img.naturalHeight !== 0)
                return Promise.resolve();
            else
                return Promise.reject(img);
        return new Promise((resolve, reject) => {
            img.addEventListener('load', resolve);
            img.addEventListener('error', () => reject(img));
        });
    })).then(() => {
        console.log('all images loaded successfully');
    }, badImg => {
        console.log('some image failed to load, others may still be loading');
        console.log('first broken image:', badImg);
    });
    

    Two latest code blocks use naturalHeight to detect broken images among the already loaded ones. This method generally works, but has some drawbacks: it is said to not work when the image URL is set via CSS content property and when the image is an SVG that doesn't have its dimensions specified. If this is the case, you'll have to refactor your code so that you set up the event handlers before the images begin to load. This can be done by specifying onload and onerror right in the HTML or by creating the img elements in the JavaScript. Another way would be to set src as data-src in the HTML and perform img.src = img.dataset.src after attaching the handlers.

    0 讨论(0)
  • 2020-12-01 06:04

    This works great:

    $(function() {
     $(window).bind("load", function() {
        // code here
     });
    });
    
    0 讨论(0)
  • 2020-12-01 06:05

    Here is a quick hack for modern browsers:

    var imgs = document.images,
        len = imgs.length,
        counter = 0;
    
    [].forEach.call( imgs, function( img ) {
        if(img.complete)
          incrementCounter();
        else
          img.addEventListener( 'load', incrementCounter, false );
    } );
    
    function incrementCounter() {
        counter++;
        if ( counter === len ) {
            console.log( 'All images loaded!' );
        }
    }
    

    Once all the images are loaded, your console will show "All images loaded!".

    What this code does:

    • Load all the images in a variable from the document
    • Loop through these images
    • Add a listener for the "load" event on each of these images to run the incrementCounter function
    • The incrementCounter will increment the counter
    • If the counter has reached the length of images, that means they're all loaded

    Having this code in a cross-browser way wouldn't be so hard, it's just cleaner like this.

    0 讨论(0)
  • 2020-12-01 06:11

    A little late to the game, but I've found the following method to be the most straightforward:

    function waitForImages () {
      let isLoading = true
    
      while (isLoading) {
        const loading = [].slice.call(document.images).filter(img => img.complete !== true)
        if (!loading.length > 0) {
          isLoading = true
          return
        }
      }
    }
    

    Note that this is blocking code (useful if you're trying to ensure images are loaded in something like phantomjs)

    0 讨论(0)
  • 2020-12-01 06:13

    I was about to suggest the same thing Baz1nga said.

    Also, another possible option that's maybe not as foolproof but easier to maintain is to pick the most important/biggest image and attach an onload event to only that one. the advantage here is that there's less code to change if you later add more images to your page.

    0 讨论(0)
提交回复
热议问题