我正在寻找一种快速简单的方法来用JavaScript预加载图像。如果重要的话,我正在使用jQuery。

我在这里(http://nettuts.com ...)看到了:

function complexLoad(config, fileNames) {
  for (var x = 0; x < fileNames.length; x++) {
    $("<img>").attr({
      id: fileNames[x],
      src: config.imgDir + fileNames[x] + config.imgFormat,
      title: "The " + fileNames[x] + " nebula"
    }).appendTo("#" + config.imgContainer).css({ display: "none" });
  }
};


但是,对于我想要的东西来说似乎有点过高了!

我知道那里有jQuery插件可以做到这一点,但是它们看上去都很大(大小);我只需要一种快速,轻松和简短的方式来预加载图像!

评论

$ .each(arguments,function(){(new Image).src = this});

#1 楼

快速简便:

function preload(arrayOfImages) {
    $(arrayOfImages).each(function(){
        $('<img/>')[0].src = this;
        // Alternatively you could use:
        // (new Image()).src = this;
    });
}

// Usage:

preload([
    'img/imageName.jpg',
    'img/anotherOne.jpg',
    'img/blahblahblah.jpg'
]);


或者,如果您想要jQuery插件:

$.fn.preload = function() {
    this.each(function(){
        $('<img/>')[0].src = this;
    });
}

// Usage:

$(['img1.jpg','img2.jpg','img3.jpg']).preload();


评论


不需要将图像元素插入DOM来确保浏览器对其进行缓存吗?

– JoshNaro
2010年8月17日15:33

我相信$('')只会在内存中创建一个图像元素(请参阅链接)。看起来'$('')实际上会在隐藏的DIV中创建元素,因为它更加“复杂”。但是,我认为大多数浏览器都不需要这样做。

– JoshNaro
2011年2月11日15:30



那是编写jQuery插件的怪异方式。为什么不$ .preload(['img1.jpg','img2.jpg'])?

– alex
2012年1月17日在2:56

确保在$(window).load(function(){/ * preload here * /})内调用此函数;因为这样可以首先加载文档中的所有图像,所以可能首先需要使用它们。

–贾斯珀·肯尼斯(Jasper Kennis)
2012年5月5日15:35

@RegionalC-为防止在设置加载事件之前完成加载图像,在设置src之前设置加载事件可能会更安全一些? $('')。load(function(){/ *已加载!* /})。attr('src',this);

–备用字节
13年2月4日在22:01

#2 楼

这是第一个响应的经过调整的版本,该响应实际上将图像加载到DOM中并默认隐藏它。

function preload(arrayOfImages) {
    $(arrayOfImages).each(function () {
        $('<img />').attr('src',this).appendTo('body').css('display','none');
    });
}


评论


hide()比css('display','none')更简洁。

– alex
2011-09-22 2:32

将它们插入DOM有什么好处?

– alex
13年5月7日在21:56

我也想知道将它们插入DOM的好处。

– jedmao
13年7月3日在23:39

根据我的经验,将图像预加载到DOM中会使浏览器意识到其存在并对其进行适当的缓存。否则,该图像仅存在于内存中,该内存仅适用于单页应用程序。

–丹尼斯·朗戈(Dennis Rongo)
13年7月4日在18:00

丹尼斯·朗戈。将图片添加到DOM可以解决Chrome上随机重新加载的问题。谢谢!

– tmorell
13年7月7日在2:53

#3 楼

使用JavaScript图像对象。

此功能允许您在加载所有图片时触发回调。但是,请注意,如果未加载至少一个资源,它将永远不会触发回调。可以通过实现onerror回调并增加loaded值或处理错误来轻松解决此问题。

var preloadPictures = function(pictureUrls, callback) {
    var i,
        j,
        loaded = 0;

    for (i = 0, j = pictureUrls.length; i < j; i++) {
        (function (img, src) {
            img.onload = function () {                               
                if (++loaded == pictureUrls.length && callback) {
                    callback();
                }
            };

            // Use the following callback methods to debug
            // in case of an unexpected behavior.
            img.onerror = function () {};
            img.onabort = function () {};

            img.src = src;
        } (new Image(), pictureUrls[i]));
    }
};

preloadPictures(['http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar'], function(){
    console.log('a');
});

preloadPictures(['http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar', 'http://foo/picture.bar'], function(){
    console.log('b');
});


评论


做正确的事,使用JavaScript Image对象。您在这些答案中发现有人做错事了吗?

– alex
13年5月7日在21:58

出色的代码。我是否认为即使缓存了图像也会触发onload事件,这是正确的吗? (因为首先声明了img.onload)。这是我的测试所显示的。

– Startec
2014年5月23日上午10:06

@alex可能,是的。如果目标是预加载(表示性能顺序),那么我希望看到一个原始的JS选项,而不是jQuery依赖的选项。

– Charlie Schliesser
14年7月15日在23:57

我喜欢这个解决方案,但是我发现它不能在Firefox中使用。是我还是其他人有同样的问题?

–万亿
2014年8月20日19:37

@Gazillion提供更多详细信息。您如何定义“无效”?什么是FF版本?

–加雷斯
14年8月20日在20:30

#4 楼

JP,检查完您的解决方案后,我在Firefox中仍然遇到问题,即在继续加载页面之前无法预加载图像。我通过在服务器端脚本中添加一些sleep(5)来发现此问题。我根据您的情况实施了以下解决方案,似乎可以解决此问题。

基本上,我向您的jQuery preload插件添加了一个回调,以便在正确加载所有图像后调用它。

// Helper function, used below.
// Usage: ['img1.jpg','img2.jpg'].remove('img1.jpg');
Array.prototype.remove = function(element) {
  for (var i = 0; i < this.length; i++) {
    if (this[i] == element) { this.splice(i,1); }
  }
};

// Usage: $(['img1.jpg','img2.jpg']).preloadImages(function(){ ... });
// Callback function gets called after all images are preloaded
$.fn.preloadImages = function(callback) {
  checklist = this.toArray();
  this.each(function() {
    $('<img>').attr({ src: this }).load(function() {
      checklist.remove($(this).attr('src'));
      if (checklist.length == 0) { callback(); }
    });
  });
};


出于兴趣,我在此使用的方法如下:
(像我一样)从Google来到此页面的人,他们正在寻找一种在Ajax调用中预加载图像的解决方案。

评论


对于那些不希望弄乱Array.prototype的人,可以执行以下操作:checklist = this.length在onload函数中:checklist--然后:if(checklist == 0)callback();

– MiniGod
2012年7月15日在0:35



一切都很好,但是向您不拥有的对象添加新方法或删除现有方法是JavaScript中最差的做法之一。

– Rihards
2012-09-10 7:17



不错,快捷,但是如果其中一张图片损坏或无法加载,则此代码将永远不会触发回调。

– SammyK
2012年10月30日在6:38

.attr({src:this})。load(function(){...})应该是.load(function(){...})。attr({src:this})否则您将遇到缓存问题。

–凯文B
13年3月27日在14:31

#5 楼

这段jQuery代码创建(并加载)了一个DOM元素img而没有显示它:

$('<img src="img/1.jpg"/>');


评论


@huzzah-您最好只使用精灵。更少的http请求。 :)

– Alex K
2012年11月16日16:28

#6 楼

$.fn.preload = function (callback) {
  var length = this.length;
  var iterator = 0;

  return this.each(function () {
    var self = this;
    var tmp = new Image();

    if (callback) tmp.onload = function () {
      callback.call(self, 100 * ++iterator / length, iterator === length);
    };

    tmp.src = this.src;
  });
};


用法非常简单:

$('img').preload(function(perc, done) {
  console.log(this, perc, done);
});


http://jsfiddle.net/yckart/ACbTK/

评论


这是一个非常好的答案,它确实应该是恕我直言的最高投票答案。

–sleepycal
14年1月24日在16:08

一些解释性的话会很好。

– Robsch
17年1月2日在8:12

好的答案,但我建议使用picsum.photos而不是lorempixel.com

– Aleksandar
19年12月26日在16:00

#7 楼

我有一个小插件可以处理这个问题。

它叫做waitForImages,它可以处理img元素或任何引用CSS中图像的元素,例如div { background: url(img.png) }

如果您只想加载所有图像,包括CSS中引用的图像,这是您的操作方法:)

$('body').waitForImages({
    waitForAll: true,
    finished: function() {
       // All images have loaded.
    }  
});


评论


这个插件会导致尚未出现在页面上的图像被加载,还是仅将事件附加到已经要加载的图像上?

–戴夫·卡梅伦(Dave Cameron)
2012年5月29日19:11

@DaveCameron它不考虑图像是否可见。您可以轻松地进行分叉并进行更改-只需将:visible添加到自定义选择器即可。

– alex
2012年5月29日23:44

这个插件看起来非常有趣。但是,jquery文档强调了将加载事件应用于图像时:“无法始终如一地或可靠地跨浏览器工作”。插件如何解决这个问题?

– EleventyOne
13年10月28日在1:11

@EleventyOne检查有关自定义选择器的源。

– alex
13-10-28在2:18

@alex这个插件如何加载元素:hover上css中设置的图像?它对我不起作用

–菲利普·霍夫曼(Philipp Hofmann)
2014年3月27日在9:14

#8 楼

您可以使用css display:none;规则在html的某处加载图片,然后在需要使用js或jquery时显示它们

不要使用js或jquery函数进行预加载只是css规则要执行的js

示例:HTML

<img src="someimg.png" class="hide" alt=""/>


css:

.hide{
display:none;
}


jQuery:

//if want to show img 
$('.hide').show();
//if want to hide
$('.hide').hide();


用jquery / javascript预加载图像效果不好,因为图像在页面中加载需要几毫秒,而您还要花费几毫秒来解析和执行脚本,尤其是如果它们是大图像,那么将它们隐藏在hml中也对性能有更好的影响,因为图像实际上是预加载的,根本看不到蜂鸣声,直到显示出来为止!

评论


有关此方法的更多信息,请参见:perishablepress.com/…

– gdelfino
2012年4月30日0:00在

但是,您需要意识到这种技术的主要缺点:在加载所有图像之前,不会完全加载页面。根据要预加载的图像数量及其大小,这可能需要一些时间。更糟糕的是,如果标记未指定高度和宽度,则某些浏览器可能会等到获取图像后再呈现页面的其余部分。

–user246645
13年2月1日在9:18

@Alex无论如何都需要加载img,您可以自由选择是否使用html加载它们,并避免任何形式的闪烁和一半加载的图像,或者如果您想获得更快的速度来获得一个不稳定的解决方案

–itsme
13年2月1日在9:46

我也真的认为用javascript创建html标签根本不可读,仅我的2美分

–itsme
13年2月1日在9:47

我需要一个非常复杂的项目的快速解决方案,就是这样。

–暴风雨
13年5月27日在8:14

#9 楼

这个jquery imageLoader插件仅1.39kb。

用法:

$({}).imageLoader({
    images: [src1,src2,src3...],
    allcomplete:function(e,ui){
        //images are ready here
        //your code - site.fadeIn() or something like that
    }
});


还有其他选项,例如是否要同步加载图像或每个图像的同步和异步事件。

评论


@AamirAfridi为什么?

–伊恩
13年5月5日在19:31

@Ian,因为在触发回调时文档已经准备就绪。 $(document).ready用于确保已加载DOM。当涉及到回调时,这意味着所有图像都已加载,这意味着已加载yoru DOM,因此在回调内部无需document.ready。

– Aamir Afridi
13年3月6日在15:09

@AamirAfridi无法保证文档已在回调中准备好……您从何处推断出该信息?插件页面上没有任何内容表明DOM准备就绪后将执行allcomplete回调。 DOM准备就绪后,图像很有可能完成加载,但没有理由假设。我不知道您为什么认为回调是神奇的,并且在DOM准备就绪后执行回调...您能解释一下从哪里获得回调吗?仅仅因为图像已加载并不意味着DOM已准备就绪

–伊恩
2013年3月6日15:47



@AamirAfridi插件的文档甚至说:注意,要将其用作图像预加载器,只需将$(document).ready(function(){});放进去。进入您的“ allcomplete”事件:>简单! ...直接推荐此答案显示的内容。

–伊恩
13年6月6日在15:49

@AamirAfridi对于这种情况,这没有任何意义。该插件是一个预加载器。您想尽快执行它。并且有很多事情与您希望尽快启动的DOM不相关,然后在DOM准备就绪时执行一些操作。

–伊恩
2013年3月6日20:27



#10 楼

快速,无插件的预加载jQuery中图像并获得回调函数的方法是一次创建多个img标签并计算响应,例如,

function preload(files, cb) {
    var len = files.length;
    $(files.map(function(f) {
        return '<img src="'+f+'" />';
    }).join('')).load(function () {
        if(--len===0) {
            cb();
        }
    });
}

preload(["one.jpg", "two.png", "three.png"], function() {
    /* Code here is called once all files are loaded. */
});
​    ​


请注意,如果要支持IE7,则需要使用这个不太漂亮的版本(在其他浏览器中也可以使用):

function preload(files, cb) {
    var len = files.length;
    $($.map(files, function(f) {
        return '<img src="'+f+'" />';
    }).join('')).load(function () {
        if(--len===0) {
            cb();
        }
    });
}


#11 楼

谢谢你!我想在JP的答案上加上一点即兴之处-我不知道这对任何人都没有帮助,但是这样一来,您不必创建图像阵列,就可以预加载所有大图像如果您的拇指正确命名。这很方便,因为我有一个用html编写所有页面的人,它确保了他们要做的少一步-消除了创建图像数组的需要,而另一步可能使事情搞砸了。

$("img").each(function(){
    var imgsrc = $(this).attr('src');
    if(imgsrc.match('_th.jpg') || imgsrc.match('_home.jpg')){
      imgsrc = thumbToLarge(imgsrc);
      (new Image()).src = imgsrc;   
    }
});


基本上,页面上的每个图像都会抓取每个图像的src,如果它符合特定条件(是拇指或首页图像),它将更改名称(在图像src中使用基本字符串替换),然后加载图像。在我的情况下,页面上到处都是拇指图像,都命名为image_th.jpg之类的东西,所有对应的大图像都命名为image_lg。 jpg。大拇指只需将_th.jpg替换为_lg.jpg,然后预加载所有大图像。

希望对您有所帮助。

#12 楼

    jQuery.preloadImage=function(src,onSuccess,onError)
    {
        var img = new Image()
        img.src=src;
        var error=false;
        img.onerror=function(){
            error=true;
            if(onError)onError.call(img);
        }
        if(error==false)    
        setTimeout(function(){
            if(img.height>0&&img.width>0){ 
                if(onSuccess)onSuccess.call(img);
                return img;
            }   else {
                setTimeout(arguments.callee,5);
            }   
        },0);
        return img; 
    }

    jQuery.preloadImages=function(arrayOfImages){
        jQuery.each(arrayOfImages,function(){
            jQuery.preloadImage(this);
        })
    }
 // example   
    jQuery.preloadImage(
        'img/someimage.jpg',
        function(){
            /*complete
            this.width!=0 == true
            */
        },
        function(){
            /*error*/
        }
    )


评论


欢迎使用Stack Overflow!而不是仅发布一段代码,请解释为什么此代码解决了所提出的问题。没有解释,这不是答案。

–马丁·彼得斯(Martijn Pieters)♦
2012年11月19日14:41

#13 楼

我使用以下代码:

$("#myImage").attr("src","img/spinner.gif");

var img = new Image();
$(img).load(function() {
    $("#myImage").attr("src",img.src);
});
img.src = "http://example.com/imageToPreload.jpg";


评论


首先绑定到load事件,然后设置src。

–凯文B
13年3月27日在14:25

#14 楼

我将使用清单文件来告诉(现代)网络浏览器以加载所有相关图像并将其缓存。使用Grunt和grunt-manifest自动执行此操作,而无需再担心预加载脚本,缓存无效器,CDN等。

https://github.com/gunta/grunt-manifest

#15 楼

即使在IE9中,这也对我有效:

$('<img src="' + imgURL + '"/>').on('load', function(){ doOnLoadStuff(); });


评论


这最终将由于缓存而失败,请始终在设置src属性之前绑定load事件。

–凯文B
2013年3月27日14:27

#16 楼

我想通过Google Maps API自定义叠加层实现此目的。他们的示例代码仅使用JS插入IMG元素,并显示图像占位符框,直到加载图像为止。我在这里找到了一个对我有用的答案:https://stackoverflow.com/a/10863680/2095698。

$('<img src="'+ imgPaht +'">').load(function() {
$(this).width(some).height(some).appendTo('#some_target');
});


这会像以前建议的那样预加载图像,并且然后在加载img URL后使用处理程序附加img对象。 jQuery的文档警告说,缓存的图像无法与此事件/处理程序代码一起很好地工作,但是它在FireFox和Chrome中对我有效,并且我不必担心IE。

评论


如您所知,这不适用于缓存的图像。解决方法是先绑定load事件,然后设置src属性。

–凯文B
2013年3月27日14:24在

#17 楼

function preload(imgs) {
    $(imgs).each(function(index, value) {
        $('<img />').attr('src', value).appendTo('body').css('display', 'none');
    });
}


.attr('src',value)
不是
.attr('src',this)

指出来:)

评论


将此范围限定在传递给$ .each的回调中,并分配给要迭代的值。

–奥贝克
13年7月28日在8:13

? $(['img1.jpg','img2.jpg','img3.jpg'])。each(function(index,value){console.log(value); // img1.jpg console.log(this) ; // String {0 =“ i”,1 =“ m”,2 =“ g”,更多...} $('')。attr('src',this).appendTo(' body')。css('display','none');});

– Whisher
13年7月29日在12:32

嗯我想你就在这里。例如$(“ div”)。each(function(i,el){console.log(el == this);});产生所有真理;数组迭代似乎表现出不同的行为。

–奥贝克
13年7月30日在18:59

#18 楼

我通常在我的项目中使用此代码段来加载页面中的图像。
您可以在这里查看结果https://jsfiddle.net/ftor34ey/

 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<img src="https://live.staticflickr.com/65535/50020763321_d61d49e505_k_d.jpg" width="100" />
<img src="https://live.staticflickr.com/65535/50021019427_692a8167e9_k_d.jpg" width="100" />
<img src="https://live.staticflickr.com/65535/50020228418_d730efe386_k_d.jpg" width="100" />
<img src="https://live.staticflickr.com/65535/50020230828_7ef175d07c_k_d.jpg" width="100" />

<div style="background-image: url(https://live.staticflickr.com/65535/50020765826_e8da0aacca_k_d.jpg);"></div>
<style>
    .bg {
        background-image: url("https://live.staticflickr.com/65535/50020765651_af0962c22e_k_d.jpg");
    }
</style>
<div class="bg"></div>

<div id="loadingProgress"></div>
 


该脚本将页面中的所有srcbackground-image保存在数组中,并全部加载。

您可以通过变量loadCount看到/阅读/显示加载进度。

 let backgroundImageArray = [];

function backgroundLoading(i) {

    let loadCount = 0;

    let img = new Image();
    $(img).on('load', function () {

        if (i < backgroundImageArray.length) {

            loadCount = parseInt(((100 / backgroundImageArray.length) * i));
            backgroundLoading(i + 1);

        } else {

            loadCount = 100;
            // do something when the page finished to load all the images
            console.log('loading completed!!!');
            $('#loadingProgress').append('<div>loading completed!!!</div>');

        }

        console.log(loadCount + '%');
        $('#loadingProgress').append('<div>' + loadCount + '%</div>');

    }).attr('src', backgroundImageArray[i - 1]);

}

$(document).ready(function () {

    $('*').each(function () {

        var backgroundImage = $(this).css('background-image');
        var putInArray = false;

        var check = backgroundImage.substr(0, 3);

        if (check == 'url') {

            backgroundImage = backgroundImage.split('url(').join('').split(')').join('');
            backgroundImage = backgroundImage.replace('"', '');
            backgroundImage = backgroundImage.replace('"', '');

            if (backgroundImage.substr(0, 4) == 'http') {
                backgroundImage = backgroundImage;
            }
            putInArray = true;

        } else if ($(this).get(0).tagName == 'IMG') {

            backgroundImage = $(this).attr('src');
            putInArray = true;

        }

        if (putInArray) {
            backgroundImageArray[backgroundImageArray.length] = backgroundImage;
        }

    });

    backgroundLoading(1);

});
 


#19 楼

咖啡脚本中有5行

array = ['/img/movie1.png','/img/movie2.png','/img/movie3.png']

$(document).ready ->
  for index, image of array
    img[index] = new Image()
    img[index].src = image


评论


您能否扩展解决方案如何解决OP中的问题?并可能注释您的代码,以便其他人可以更轻松地理解它?

–Ro Yo Mi
13年8月10日在0:25

#20 楼

对于那些只懂一点动作脚本的人,您可以轻松地检查Flash Player,并制作Flash预加载器,也可以将其导出到html5 / Javascript / Jquery。
如果Flash Player是未检测到,请查看有关如何使用youtube角色将其返回html5播放器的示例:)
并创建自己的示例。
我没有详细信息,因为我还没有开始,如果我没有忘了,我稍后再发布,将尝试一些标准的Jquery代码来挖掘。

评论


这不是解决方案。浏览器默认情况下不支持Flash Player。使用本机浏览器语言JavaScript可以轻松实现。

–乌斯曼·艾哈迈德(Usman Ahmed)
17年5月5日17:56

我记得2012年的Flash仇恨者...这是不正常的...到处走走,我什至都用Flash来攻击我。

– Peter Gruppelaar
17年5月6日在19:08