支持事件的图像预加载器 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 <img>
元素上无限次地执行此操作,而无需替换它们。
我们可以使用 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的主要内容,如果未能解决你的问题,请参考以下文章