【问题标题】:Image preloader javascript that supports events支持事件的图像预加载器 javascript
【发布时间】:2012-01-06 01:31:41
【问题描述】:

我正在尝试查找图像预加载器脚本。

虽然我找到了一些,但它们都不支持在预加载完成时触发的事件。

有没有人知道任何脚本或 jQuery 插件可以做到这一点?

希望这个问题适合 stackoverflow - 如果不适合,请随时将其删除。

【问题讨论】:

    标签: javascript jquery image preloader preloading


    【解决方案1】:

    这是一个函数,它将从数组中预加载图像并在最后一个完成时调用您的回调:

    function preloadImages(srcs, imgs, callback) {
        var img;
        var remaining = srcs.length;
        for (var i = 0; i < srcs.length; i++) {
            img = new Image();
            img.onload = function() {
                --remaining;
                if (remaining <= 0) {
                    callback();
                }
            };
            img.src = srcs[i];
            imgs.push(img);
        }
    }
    
    // then to call it, you would use this
    var imageSrcs = ["src1", "src2", "src3", "src4"];
    var images = [];
    
    preloadImages(imageSrcs, images, myFunction);
    

    由于我们现在正处于使用 Promise 进行异步操作的时代,这里有一个使用 Promise 并通过 ES6 标准 Promise 通知调用者的上述版本:

    function preloadImages(srcs) {
        function loadImage(src) {
            return new Promise(function(resolve, reject) {
                var img = new Image();
                img.onload = function() {
                    resolve(img);
                };
                img.onerror = img.onabort = function() {
                    reject(src);
                };
                img.src = src;
            });
        }
        var promises = [];
        for (var i = 0; i < srcs.length; i++) {
            promises.push(loadImage(srcs[i]));
        }
        return Promise.all(promises);
    }
    
    preloadImages(["src1", "src2", "src3", "src4"]).then(function(imgs) {
        // all images are loaded now and in the array imgs
    }, function(errImg) {
        // at least one image failed to load
    });
    

    还有,这是一个使用 2015 jQuery 承诺的版本:

    function preloadImages(srcs) {
        function loadImage(src) {
            return new $.Deferred(function(def) {
                var img = new Image();
                img.onload = function() {
                    def.resolve(img);
                };
                img.onerror = img.onabort = function() {
                    def.reject(src);
                };
                img.src = src;
            }).promise();
        }
        var promises = [];
        for (var i = 0; i < srcs.length; i++) {
            promises.push(loadImage(srcs[i]));
        }
        return $.when.apply($, promises).then(function() {
            // return results as a simple array rather than as separate arguments
            return Array.prototype.slice.call(arguments);
        });
    }
    
    preloadImages(["src1", "src2", "src3", "src4"]).then(function(imgs) {
        // all images are loaded now and in the array imgs
    }, function(errImg) {
        // at least one image failed to load
    });
    

    【讨论】:

    • 为了这个函数的完整性,您可以添加 onerror 处理程序、onabort 处理程序和超时,这样如果一个或多个图像加载有问题并且永远不会成功完成,您仍然可以调用您的回调。如果图像没有加载错误,它将正常工作。
    • 是的,这很好。我试图证明这一点,但我失败了。
    • 添加了使用 Promise 的 preloadImages() 函数版本,包括标准 ES6 Promise 和 jQuery Promise。
    • 在我看来,新添加的内容缺少 img.src = src;之后 var img = new Image();
    【解决方案2】:

    要获得更强大的解决方案,请考虑使用带有几个回调 (jsFiddle) 的 PRELOADER 函数。

    保持简单:

    在此示例中,我在 Object 文字 PRELOADER_OBJECT 中传递回调和图像哈希,然后覆盖 PRELOADER 中的回调:

    // preloder object stores image hash
    // and event handler callbacks
    var PRELOADER_OBJECT = {
    
        imgArray:"http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg http://torwars.com/wp-content/uploads/2012/02/chewbacca-w-han-solo-anh.jpg".split(" "),
    
        progressCallback : function( percent )
        {
            $( '#preloader_progress' ).html( 'preload progress complete : ' + percent + '%' );
            console.log( 'preload progress complete : ', percent );
        },
    
        completeCallback : function( scope )
        {
            // hide preload indicator, do something when finished
            console.log( 'preload complete!' );
            $( '#preloader_modal' ).delay( 1000 ).animate( { opacity : 0 }, function( )
            {
                $( '.preload_class' ).each( function( index )
                {
                    $( this ).delay( index * 100 ).animate( { opacity : 0 } );
                } );
            } );
        }
    
    /*Localize params and create PRELOADER object. 
    Needs to loadImages( ); iterate through hash and 
    call onPreloadProgress( ) and onPreloadComplete( )
    each time until finished. If you're still within
    bounds of the image hash, call progressCallback( )
    recursively. When finished, fire onCompleteCallback( )*/
    
    var PRELOADER = function( object )
    {
        // preloader modal overlay
        this.modal = undefined;
    
        // progress indicator container
        this.progressIndicator = undefined;
    
        // image preload progress
        this.progress = undefined;
    
        // progress callback
        this.progressCallback = undefined;
    
        // complete callback
        this.completeCallback = undefined;
    
        // hash to store key : value pairs for image paths
        this.imgArray = undefined; 
    
        // store images in preloadArray
        this.preloadArray = [];
    
        // initialize and localize our data
        this.initialize = function( )
        {
            // create preload indicator and overlay modal
            this.createPreloaderModal( );
    
            // image hash
            this.imgArray = object.imgArray;
    
            // progress callback event handler
            this.progressCallback = object.progressCallback;
    
            // complete callback event
            this.completeCallback = object.completeCallback;
    
            // load images
            this.loadImages( );
        };
    
        this.progressCallback = function( ) {}; // function to override
    
        this.completeCallback = function( ) {}; // function to override
    
        // load images into DOM and fire callbacks
        this.loadImages = function( )
        {
            var that = this;
    
            // iterate through hash and place images into DOM
            $.each( PRELOADER_OBJECT.imgArray, function( index, object )
            {
                this.image = $( "<img/>", { "src" : object, "class": "preload_class" } ).appendTo( 'body' );
    
                // mark progress and call progressCallback( ) event handler
                that.progress = Math.ceil( ( index / PRELOADER_OBJECT.imgArray.length ) * 100 );
                that.progressCallback( this.progress );
    
                that.preloadArray.push( this.image );
            } );
    
            // check for array bounds and call completeCallback( )
            if ( PRELOADER_OBJECT.imgArray.length )
            {
                this.progressCallback( 100 );
                this.completeCallback( this );
            }
        };
    
        // create modal to display preload data
        this.createPreloaderModal = function( )
        {
            this.modal = $( '<div/>', { 'id' : 'preloader_modal' } ).appendTo( 'body' );
            this.progressIndicator = $( '<h1/>', { 'id' : 'preloader_progress' } ).appendTo( this.modal );
        };
    };
    
    // trigger event chain when DOM loads
    $( document ).ready( function( )
    {    
        // instantiate PRELOADER instance and pass
        // our JSON data model as a parameter
        var preloader = new PRELOADER( PRELOADER_OBJECT );
    
        // initialize preloader
        preloader.initialize( );
    } );
    

    };​

    当网站负载大到需要图像预加载器时,可以轻松修改模态文本显示以支持数据驱动的 jQuery 动画。

    【讨论】:

      【解决方案3】:

      预加载和加载是一回事。您可以插入图像(创建新图像或更改现有图像的“src”属性),但使用$("element").hide() 或类似方法隐藏元素。在你这样做之前,像这样附加一个加载事件处理程序:

      var images = ["src1", "src2", "src3", "src4"];
      var len = images.length;
      
      for(i=0; i<len; i++){
          $("parent element").html('<img id="new-img" style="display:none;" src="'+images[i]+'"/>');
          $("new-img").load(function(){
              //Your image is now "preloaded"
      
              //Now you can show the image, or do other stuff
              $(this).show();
          });
      }
      

      【讨论】:

      • 谢谢你,西蒙。我正在尝试将其设置为联系人地图,其中要显示一个国家的部分地区,每个地区都是 PNG,非常大。我想预加载整个东西,然后在其容器中添加一个类名以使其可见。差不多就是这样。但是附加一个回调来触发加载单个图像并不是我想要的。
      • “预加载”是什么意思?我假设你想在用户需要它之前加载它,这样当他/她想看到它时,它不需要一千年才能出现。使用上面的代码加载图像,一旦加载,您可以存储对它的引用,以便在用户需要查看时引用它。这有效地预加载了图像。
      • 谢谢,我明白了,但这不是我想要的。我正在尝试找到一个脚本,该脚本可以提供一组图像源,将它们加载到后台,然后触发一个事件。
      • 每次图像加载完成后,执行 var++,如果 var == 要预加载的图像数量,则运行“所有已加载”例程
      【解决方案4】:

      预加载需要一些额外的工作,比如创建新的图像元素,监控它们是否都已加载,然后用 DOM 中的现有元素替换它们。但是,您可以直接在 DOM &lt;img&gt; 元素上无限次地执行此操作,而无需替换它们。

      我们可以使用 Fetch API 来访问图片,等到它们都下载到 promise.all() 中,然后在最合适的时间使用window.requestAnimationFrame().

      在以下示例中,我将img 元素的src 属性刷新10 次。根据延迟,我正在使用从 API 加载 4 个图像所需的时间。因此,一旦我们加载了所有图像,我会立即通过递归调用相同的 refreshImagesNTimes 函数来发出新请求。

      您当然可以选择一次加载任意数量的图像块,并使用简单的setTimeout 机制以精确的时间间隔分组显示它们。

      function refreshImagesNTimes(nodeList,count = -1){
        var imgPromises = Array.from({length: nodeList.length})
                               .map(_ => fetch("https://unsplash.it/480/640/?random").then(res => res.blob()));
        Promise.all(imgPromises)
               .then(function(blobs){
                       window.requestAnimationFrame(_ => nodeList.forEach((img, i) => img.src = (window.URL || window.webkitURL).createObjectURL(blobs[i])));
                       --count && refreshImagesNTimes(nodeList, count);
                     });
      }
      
      var images = document.querySelectorAll("#container img");
      refreshImagesNTimes(images,10);
      #container {
        display: flex;
        flex-wrap: wrap;
        justify-content: space-evenly;
        align-items: center;
        margin: auto;
        width: 75vw;
        height: 56.25vw;
        background-color: #000;
        box-sizing: border-box;
      }
      
      img {
        width: 45%;
        height: 45%;
        background-color: thistle;
      }
      <div id="container">
        <img>
        <img>
        <img>
        <img>
      </div>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-02
        相关资源
        最近更新 更多