我完全意识到这个问题已经被问到并在任何地方得到了回答,无论是在 SO 还是在关闭。但是,每次似乎都有不同的答案,例如this、this和that。
我不在乎它是否使用 jQuery - 重要的是它可以工作,并且是跨浏览器的。]
那么,预加载图像的最佳方法是什么?
不幸的是,这取决于你的目的。如果您打算将图像用于样式目的,那么最好的选择是使用精灵。 http://www.alistapart.com/articles/sprites2
但是,如果您打算在 <img> 标签中使用图像,那么您需要预先加载它们
function preload(sources)
{
var images = [];
for (i = 0, length = sources.length; i < length; ++i) {
images[i] = new Image();
images[i].src = sources[i];
}
}
(修改后的源代码取自What is the best way to preload multiple images in JavaScript?)
usingnew Image()
不涉及使用 DOM 方法的费用,但对指定图像的新请求将被添加到队列中。由于图像此时并未实际添加到页面中,因此不涉及重新渲染。但是,我建议将其添加到页面的末尾(如果可能,所有脚本都应该如此)以防止它包含更多关键元素。
编辑:编辑以正确反映评论,指出需要单独Image
的对象才能正常工作。谢谢,我很遗憾没有更仔细地检查它。
Edit2:编辑使可重用性更加明显
编辑3(3年后):
由于浏览器处理不可见图像的方式发生了变化(显示:无,或者,如本答案所示,从未附加到文档中),因此首选一种新的预加载方法。
您可以使用 Ajax 请求来强制提前检索图像。使用 jQuery,例如:
jQuery.get(source);
或者在我们之前的例子中,你可以这样做:
function preload(sources)
{
jQuery.each(sources, function(i,source) { jQuery.get(source); });
}
请注意,这不适用于按原样正常的精灵的情况。这仅适用于照片画廊或带有图像的滑块/轮播等图像未加载的内容,因为它们最初不可见。
另请注意,此方法不适用于 IE(通常不使用 ajax 来检索图像数据)。
雪碧
正如其他人所提到的,由于各种原因,精灵效果很好,但是,它并没有想象中的那么好。
不过,处理不规则形状很棘手。将所有新图像合并到新图像中是另一种烦恼。
使用 <img> 标签的低插孔方法
如果您正在寻找最明确的解决方案,那么您应该采用我仍然喜欢的低插孔方法。在文档末尾创建指向图像的 <img> 链接,并将 and 设置width
为height
1x1 像素,另外将它们放在隐藏的 div 中。如果它们位于页面末尾,它们将在其他内容之后加载。
截至 2013 年 1 月,此处描述的所有方法都不适用于我,所以这里是替代方法,测试并使用 Chrome 25 和 Firefox 18。使用 jQuery 和这个插件来解决加载事件的怪癖:
function preload(sources, callback) {
if(sources.length) {
var preloaderDiv = $('<div style="display: none;"></div>').prependTo(document.body);
$.each(sources, function(i,source) {
$("<img/>").attr("src", source).appendTo(preloaderDiv);
if(i == (sources.length-1)) {
$(preloaderDiv).imagesLoaded(function() {
$(this).remove();
if(callback) callback();
});
}
});
} else {
if(callback) callback();
}
}
用法:
preload(['/img/a.png', '/img/b.png', '/img/c.png'], function() {
console.log("done");
});
请注意,如果缓存被禁用,您将得到不同的结果,当开发者工具打开时,默认情况下在 Chrome 上是这样,所以请记住这一点。
在我看来,使用一些库引入的 Multipart XMLHttpRequest 将是未来几年的首选解决方案。但是 IE < v8,仍然不支持 data:uri(即使 IE8 支持有限,最多允许 32kb)。这是并行图像预加载的实现 - http://code.google.com/p/core-framework/wiki/ImagePreloading,它捆绑在框架中,但仍然值得一看。
这是很久以前的,所以我不知道还有多少人对预加载图像感兴趣。
我的解决方案更加简单。
我只是使用CSS。
#hidden_preload {
height: 1px;
left: -20000px;
position: absolute;
top: -20000px;
width: 1px;
}
这是我的简单解决方案,加载后图像淡入。
function preloadImage(_imgUrl, _container){
var image = new Image();
image.src = _imgUrl;
image.onload = function(){
$(_container).fadeTo(500, 1);
};
}
对于我的用例,我有一个带有全屏图像的轮播,我想预加载它。但是,由于图像按顺序显示,并且每个加载可能需要几秒钟,因此按顺序加载它们很重要。
为此,我使用了异步库的waterfall()
方法(https://github.com/caolan/async#waterfall)
// Preload all images in the carousel in order.
image_preload_array = [];
$('div.carousel-image').each(function(){
var url = $(this).data('image-url');
image_preload_array.push(function(callback) {
var $img = $('<img/>')
$img.load(function() {
callback(null);
})[0].src = url;
});
});
async.waterfall(image_preload_array);
这是通过创建一个函数数组来工作的,每个函数都被传递了callback()
它需要执行的参数,以便调用数组中的下一个函数。的第一个参数callback()
是一个错误信息,如果提供了非空值,它将退出序列,所以我们每次都传递null。