支持事件的图像预加载器 javascript

Posted

技术标签:

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

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

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

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

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

【问题讨论】:

【参考方案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>

【讨论】:

以上是关于支持事件的图像预加载器 javascript的主要内容,如果未能解决你的问题,请参考以下文章

CSS 通用图像预加载器(微调器)

如何在 HTML 5 中为音频、视频、css、图像创建预加载器?

Adobe AIR - 带有图像的自定义预加载器

javascript 图像预加载器

javascript 图像预加载器

JavaScript 图像预加载器