图像加载时的jQuery回调(即使图像已缓存)


291

我想要做:

$("img").bind('load', function() {
  // do stuff
});

但是,从缓存加载图像时,不会触发load事件。jQuery文档建议使用一个插件来解决此问题,但无法正常工作


12
由于您的问题,一切都变了。损坏的插件已移至要点,后来又移至带有小插件jQuery.imagesLoaded的存储库。他们解决了所有小的浏览器怪癖
洛德(Lode)

上面提到的JQuery库对我来说很好用。谢谢!
plang 2012年

谢谢您的插件,它工作正常。
onimojo 2012年

Answers:


572

如果src已经设置了,则在绑定事件处理程序之前,将在缓存的情况下触发事件。要解决此问题,您可以循环检查并基于off触发事件.complete,如下所示:

$("img").one("load", function() {
  // do stuff
}).each(function() {
  if(this.complete) {
      $(this).load(); // For jQuery < 3.0 
      // $(this).trigger('load'); // For jQuery >= 3.0 
  }
});

注意从.bind()到的更改,.one()因此事件处理程序不会运行两次。


8
您的解决方案对我来说是完美的,但是我想了解一些事情,何时将运行“ if(this.complete)”代码,图像内容加载之后还是之前?因为据我从此.each可以理解,您正在所有$(“ img”)上循环播放,并且可能图像内容为空并且不会发生加载。嗯,我想我有一些遗漏,如果您能形容那是为了更好地理解它,那就太好了。谢谢。
Amr Elgarhy,2011年

33
自从您回答以来,情况已经改变。现在有一个小的工作插件jQuery.imagesLoaded。他们解决了所有小的浏览器怪癖
洛德(Lode)

3
我会setTimeout(function(){//do stuff},0)在“加载”函数中添加一个... 0会给浏览器系统(DOM)一个额外的滴答声,以确保所有内容均已正确更新。
dsdsdsdsd 2013年

14
@Lode-这是一个巨大的插件,无论规模大小都不小!
VSYNC

5
由于JQuery 3方法.load()不会触发事件并且具有1个必需参数,请.trigger("load")改用
ForceUser

48

我可以建议您将其重新加载到非DOM图像对象中吗?如果已缓存,则将完全不需要时间,并且onload仍会触发。如果未缓存,它将在加载图像时触发onload,这应该与图像的DOM版本完成加载的时间相同。

Javascript:

$(document).ready(function() {
    var tmpImg = new Image() ;
    tmpImg.src = $('#img').attr('src') ;
    tmpImg.onload = function() {
        // Run onload code.
    } ;
}) ;

更新(以处理多个图像并带有正确排序的onload附件):

$(document).ready(function() {
    var imageLoaded = function() {
        // Run onload code.
    }
    $('#img').each(function() {
        var tmpImg = new Image() ;
        tmpImg.onload = imageLoaded ;
        tmpImg.src = $(this).attr('src') ;
    }) ;
}) ;

1
您应该尝试在添加load处理程序之前将其附加,这也将不起作用,但是对于一个图像,OP代码对许多人都有效:)
Nick Craver

谢谢,我添加了更新的版本,希望能解决这两个问题。
古斯(Gus)

#img是一个ID而不是元素选择器:)也this.src可以使用,不需要在不需要的地方使用jQuery :)但是,无论哪种情况,创建另一个图像似乎都是过分的。
尼克·克雷弗

应该是$('img')。但解决方案也是2k15中的gr8
Dimag Kharab

另外,对于多图像情况,如果要对中的每个图像的DOM元素进行操作imageLoaded,请使用tmp.onload = imageLoaded.bind(this)
blisstdev

38

我的简单解决方案,它不需要任何外部插件,对于一般情况应该足够了:

/**
 * Trigger a callback when the selected images are loaded:
 * @param {String} selector
 * @param {Function} callback
  */
var onImgLoad = function(selector, callback){
    $(selector).each(function(){
        if (this.complete || /*for IE 10-*/ $(this).height() > 0) {
            callback.apply(this);
        }
        else {
            $(this).on('load', function(){
                callback.apply(this);
            });
        }
    });
};

像这样使用它:

onImgLoad('img', function(){
    // do stuff
});

例如,要使图像在加载时淡入淡出,您可以执行以下操作:

$('img').hide();
onImgLoad('img', function(){
    $(this).fadeIn(700);
});

或者,如果您喜欢类似jquery插件的方法,请执行以下操作:

/**
 * Trigger a callback when 'this' image is loaded:
 * @param {Function} callback
 */
(function($){
    $.fn.imgLoad = function(callback) {
        return this.each(function() {
            if (callback) {
                if (this.complete || /*for IE 10-*/ $(this).height() > 0) {
                    callback.apply(this);
                }
                else {
                    $(this).on('load', function(){
                        callback.apply(this);
                    });
                }
            }
        });
    };
})(jQuery);

并以这种方式使用它:

$('img').imgLoad(function(){
    // do stuff
});

例如:

$('img').hide().imgLoad(function(){
    $(this).fadeIn(700);
});

urm ..如果我的图像设置了CSS尺寸怎么办?
Simon_Weaver

widthmax-height和假height:auto,经常有必要设置宽度和只有当你需要放大图片的高度; 为了获得更强大的解决方案,我将使用ImagesLoaded之
guari 2015年

1
是的,这是一个大话,jsdoc还可以,我更正了线路示例
guari

1
带有$ .fn.imgLoad的此解决方案可跨浏览器工作。修复它会更好:&& / *对于IE 10-* / this.naturalHeight> 0该行不会考虑css样式,因为img可以被阻止但具有高度。在IE10中工作
Patryk Padus

1
这确实有一个(小的)竞争条件。映像可以在脚本的不同线程中加载,因此可以在完成检查和附加onload事件之间加载,在这种情况下不会发生任何事情。通常JS与渲染是同步的,因此您不必担心竞争条件,但这是一个例外。 html.spec.whatwg.org/multipage/...
Mog0

23

您真的必须使用jQuery吗?您也可以将onload事件直接附加到图像上;

<img src="/path/to/image.jpg" onload="doStuff(this);" />

无论是否从缓存加载图像,它都会在每次加载图像时触发。


5
没有内联javascript,它会更干净
hazelnut 2013年

1
嗨,Bjorn,onload当从缓存中第二次加载图像时,处理程序会触发吗?
SexyBeast

1
@Cupidvogel不,不会。
广告

3
杜德(Dude),您救了我的命,我尝试了至少十二种其他解决方案,而您的解决方案是唯一有效的解决方案。我正在认真考虑要再创建10个帐户,以将您的答案再投票10次。严重的谢谢!
卡罗

1
我从不了解人们对内联JS的厌恶。图像加载是独立进行的,与页面加载其余过程无关。因此,这是获得有关图像加载完成的即时反馈的唯一有效解决方案。但是,如果有人需要等待jQuery加载并且以后再发生,那么他们将不必在这里使用简单的解决方案,而要使用其他解决方案之一(Piotr的解决方案可能是最好的选择,因为它不依赖于伪代码,骇客,但guari的height()检查可能也很重要)。处理队列也可能有用。
CubicleSoft

16

您还可以将以下代码与支持加载错误一起使用:

$("img").on('load', function() {
  // do stuff on success
})
.on('error', function() {
  // do stuff on smth wrong (error 404, etc.)
})
.each(function() {
    if(this.complete) {
      $(this).load();
    } else if(this.error) {
      $(this).error();
    }
});

1
这对我来说效果最好。我认为关键是先设置load处理程序,然后再在each函数中调用它。
GreenRaccoon16年

使用下面的代码设置图像''var img = new Image(); img.src = sosImgURL; $(img).on(“ load”,function(){''
imdadhusen

13

我本人只是遇到了这个问题,到处搜索了不涉及杀死我的缓存或下载插件的解决方案。

我没有立即看到此线程,所以我找到了其他有趣的修复程序,并且(我认为)值得在此处发布:

$('.image').load(function(){
    // stuff
}).attr('src', 'new_src');

我实际上是从这里的评论中得到这个想法的:http : //www.witheringtree.com/2009/05/image-load-event-binding-with-ie-using-jquery/

我不知道它为什么起作用,但是我已经在IE7上对其进行了测试,以及它在现在起作用之前在哪里破裂。

希望能帮助到你,

编辑

接受的答案实际上说明了原因:

如果已经设置了src,那么在绑定事件处理程序之前,事件将在有案例的缓存中触发。


4
我已经在许多浏览器中测试过此功能,却没有发现它在任何地方都失败。我曾经$image.load(function(){ something(); }).attr('src', $image.attr('src'));重设原始来源。
2013年

我发现这种方法在iOS上不起作用,至少对于Safari / 601.1和Safari / 602.1不起作用
cronfy

找出原因,这是很棒的,它在什么浏览器中?
Sammaye '17

5

通过使用jQuery用图像的src生成新图像,并直接为其分配load方法,当jQuery完成生成新图像时,将成功调用load方法。这在IE 8、9和10中为我工作

$('<img />', {
    "src": $("#img").attr("src")
}).load(function(){
    // Do something
});

对于那些使用__rjs.erb模板并通过远程请求使用Ruby on Rails的用户,这是我找到的唯一解决方案。因为在js.erb中使用了局部函数,所以它会失去de绑定($(“#img” .on(“ load”)...,对于图像,则不可能委托“ on”方法:$(“ body”)。 on(“ load”,“#img”,function()...
阿尔伯特·卡塔拉

5

我找到了一个解决方案https://bugs.chromium.org/p/chromium/issues/detail?id=7731#c12 (此代码直接从注释中获取)

var photo = document.getElementById('image_id');
var img = new Image();
img.addEventListener('load', myFunction, false);
img.src = 'http://newimgsource.jpg';
photo.src = img.src;

这正是我想要的。服务器上传来一张图像。我想预装然后上菜。不能像许多答案一样选择所有图像。好一个
凯庆

4

对GUS示例的修改:

$(document).ready(function() {
    var tmpImg = new Image() ;
    tmpImg.onload = function() {
        // Run onload code.
    } ;

tmpImg.src = $('#img').attr('src');
})

在加载之前和之后设置源。


就像@Gus的答案一样,这不适用于多张图片...并且不需要src在附加onload处理程序之前设置,一旦之后就足够了。
尼克·克拉弗

3

定义img对象后,只需在另一行上重新添加src参数即可。这将诱使IE触发小伙子事件。这很丑陋,但这是我到目前为止发现的最简单的解决方法。

jQuery('<img/>', {
    src: url,
    id: 'whatever'
})
.load(function() {
})
.appendTo('#someelement');
$('#whatever').attr('src', url); // trigger .load on IE

1

如果您想这样做,我可以给您一些提示:

<div style="position:relative;width:100px;height:100px">
     <img src="loading.jpg" style='position:absolute;width:100px;height:100px;z-index:0'/>
     <img onLoad="$(this).fadeIn('normal').siblings('img').fadeOut('normal')" src="picture.jpg" style="display:none;position:absolute;width:100px;height:100px;z-index:1"/>
</div>

如果您在浏览器缓存图片时执行此操作,则始终显示img没问题,而是在真实图片下加载img。


1

我在IE中遇到此问题,其中e.target.width不确定。加载事件将触发,但是我无法在IE中获取图像的尺寸(chrome + FF有效)。

原来,您需要查找e.currentTarget.naturalWidthe.currentTarget.naturalHeight

IE再次以自己的方式(更复杂)进行操作。


0

您可以使用JAIL插件解决问题,该插件还允许您延迟加载图像(提高页面性能)并将回调作为参数传递

$('img').asynchImageLoader({callback : function(){...}});

HTML应该看起来像

<img name="/global/images/sample1.jpg" src="/global/images/blank.gif" width="width" height="height" />

0

如果您需要纯CSS解决方案,此技巧非常有效-使用transform对象。无论是否缓存图像,这也适用于图像:

CSS:

.main_container{
    position: relative;
    width: 500px;
    height: 300px;
    background-color: #cccccc;
}

.center_horizontally{
  position: absolute;
  width: 100px;
  height: 100px;
  background-color: green;
  left: 50%;
  top: 0;
  transform: translate(-50%,0);
}

.center_vertically{
  position: absolute;
  top: 50%;
  left: 0;
  width: 100px;
  height: 100px;
  background-color: blue;
  transform: translate(0,-50%);
}

.center{
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100px;
  height: 100px;
  background-color: red;
  transform: translate(-50%,-50%);
}

HTML:

<div class="main_container">
  <div class="center_horizontally"></div>
  <div class="center_vertically"></div>
  <div class="center"></div>
  </div>
</div

Codepen示例

Codepen LESS示例


您能否举一个示例说明如何在图像加载中工作?
Hastig Zusammenstellen
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.