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

Posted

技术标签:

【中文标题】图像加载时的 jQuery 回调(即使图像被缓存)【英文标题】:jQuery callback on image load (even when the image is cached) 【发布时间】:2011-04-22 01:54:06 【问题描述】:

我想做:

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

但是从缓存中加载图像时不会触发 load 事件。 The jQuery docs 建议 a plugin 解决此问题,但 it doesn't work

【问题讨论】:

自从你的问题发生了变化。损坏的插件被移到了一个 gist 中,后来被移到了一个带有 小型工作插件 jQuery.imagesLoaded 的 repo 中。他们修复了所有little browser quirks。 上面提到的 JQuery 库对我来说工作得很好。谢谢! 感谢插件,它运行良好。 【参考方案1】:

如果src 已设置,则事件在缓存案例中触发,甚至在您绑定事件处理程序之前。要解决此问题,您可以循环检查和触发基于 .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() 的更改,因此事件处理程序不会运行两次。

【讨论】:

您的解决方案对我来说非常完美,但我想了解一些事情,这个代码“if(this.complete)”什么时候运行,在图像内容加载之后还是之前?因为据我所知, .each 您正在循环所有 $("img") 并且可能是图像内容为空并且不会发生加载。嗯,我想我缺少一些东西,如果你能描述它会更好地理解它,那就太好了。谢谢。 自从你的回答发生了变化。现在有一个小型工作插件jQuery.imagesLoaded。他们修复了所有little browser quirks。 我会在“加载”函数中添加一个setTimeout(function()//do stuff,0) ... 0 为浏览器系统 (DOM) 提供了一个额外的勾号,以确保所有内容都正确更新. @Lode - 这是一个巨大的插件,在任何规模上都不小!! 由于 JQuery 3 方法 .load() 不会触发事件并且有 1 个必需参数,请改用 .trigger("load")【参考方案2】:

我可以建议您将其重新加载到非 DOM 图像对象中吗?如果它被缓存,这将不会花费任何时间,并且 onload 仍然会触发。如果没有缓存,它会在图片加载时触发 onload,这应该与图片的 DOM 版本完成加载的时间相同。

javascript

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

更新(以处理多个图像和正确排序的加载附件):

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

【讨论】:

你应该尝试附加load处理程序之前它被添加,这也不起作用,但对于一个图像,OPs代码适用于许多:)跨度> 谢谢,我添加了一个更新版本,希望能解决这两个问题。 #img 是一个 ID 而不是一个元素选择器 :) this.src 也可以工作,不需要在不需要的地方使用 jQuery :) 但是在这两种情况下创建另一个图像似乎有点矫枉过正 IMO . 应该是 $('img') 。但解决方案也是 2k15 中的 gr8 另外,对于多图的情况,如果要对imageLoaded中的每张图的DOM元素进行操作,则使用tmp.onload = imageLoaded.bind(this)【参考方案3】:

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

/**
 * 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 设置的尺寸怎么办? 设置widthmax-height,离开height:auto,通常只有在需要拉伸图片时才需要同时设置宽高;对于更强大的解决方案,我会使用像 ImagesLoaded 这样的插件 是的,输入错误,jsdoc 没问题,我更正了示例行 这个带有 $.fn.imgLoad 的解决方案可以跨浏览器工作。修复它会更好: && /*for IE 10-*/ this.naturalHeight > 0 这行不会考虑 css 样式,因为 img 可以被阻止但有高度。在 IE10 中工作 这确实有一个(小)竞争条件。图像可以在脚本的不同线程中加载,因此可以在完成检查和附加 onload 事件之间加载,在这种情况下不会发生任何事情。通常 JS 与渲染同步,因此您不必担心竞争条件,但这是一个例外。 html.spec.whatwg.org/multipage/…【参考方案4】:

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

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

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

【讨论】:

没有内联javascript会更干净 嗨,Bjorn,当第二次从缓存加载图像时,onload 处理程序会触发吗? @Cupidvogel 不会的。 老兄,你救了我的命,我已经尝试了至少十几种其他解决方案,而你的解决方案是唯一有效的。我正在认真考虑再创建 10 个帐户,让您的答案再投票 10 次。非常感谢! 我一直不明白人们对内联 JS 的厌恶。图像加载与页面加载过程的其余部分分开发生并且不按顺序进行。因此,这是获得有关图像加载完成的即时反馈的唯一有效解决方案。但是,如果有人需要等待 jQuery 加载并且稍后发生,那么他们将不得不在这里不使用简单的解决方案并使用其他解决方案之一(Piotr 可能是最好的选择,因为它不依赖于伪hacks 但 guari 的 height() 检查可能也很重要)。处理队列也很有用。【参考方案5】:

您也可以使用此代码支持加载错误:

$("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();
    
);

【讨论】:

这个最适合我。我认为关键是先设置load处理程序,然后在each函数中调用它。 使用下面的代码设置图像 ''var img = new Image(); img.src = sosImgURL; $(img).on("加载", function () ''【参考方案6】:

我自己也遇到了这个问题,到处寻找不涉及杀死我的缓存或下载插件的解决方案。

我没有立即看到这个帖子,所以我发现了一些别的东西,这是一个有趣的修复并且(我认为)值得在这里发布:

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

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

我不知道它为什么会起作用,但我已经在 IE7 上对其进行了测试,并且在它现在起作用之前它在哪里坏了。

希望对你有帮助,

编辑

接受的答案实际上解释了原因:

如果 src 已经设置,那么在绑定事件处理程序之前,事件会在缓存中触发。

【讨论】:

我已经在很多浏览器中测试过它并且没有发现它在任何地方都失败了。我使用$image.load(function() something(); ).attr('src', $image.attr('src')); 重置原始来源。 我发现这种方法在 ios 上不起作用,至少对于 Safari/601.1 和 Safari/602.1 很高兴知道为什么,它在什么浏览器中?【参考方案7】:

通过jQuery使用图片的src生成一张新图片,并直接将load方法赋值给该图片,当jQuery完成生成新图片时,load方法调用成功。这在 IE 8、9 和 10 中对我有用

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

【讨论】:

对于那些使用 Ruby on Rails、远程请求、使用 __rjs.erb 模板的用户,这是我找到的唯一解决方案。因为在 js.erb 中使用 partials,它失去了 de 绑定 ($("#img".on("load")... 并且对于图像不可能委派 "on" 方法:$("body")。 on("load","#img",function()...【参考方案8】:

我找到的解决方案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;

【讨论】:

这正是我想要的。一张图片来自服务器。我想预加载它然后发球。不像许多答案那样选择所有图像。不错。【参考方案9】:

对 GUS 示例的修改:

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

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

在onload之前和之后设置源。

【讨论】:

就像@Gus 的回答一样,这不适用于多张图片...并且无需在附加onload 处理程序之前设置src,之后一次就足够了。跨度> 【参考方案10】:

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

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

【讨论】:

【参考方案11】:

如果你想这样做,我可以给你一个小提示:

<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是没有问题的。

【讨论】:

【参考方案12】:

我在 IE 中遇到了这个问题,其中 e.target.width 未定义。 load 事件会触发,但我无法在 IE 中获得图像的尺寸(chrome + FF 有效)。

原来你需要寻找 e.currentTarget.naturalWidthe.currentTarget.naturalHeight

IE 再次以自己(更复杂)的方式做事。

【讨论】:

【参考方案13】:

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

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

HTML 应该看起来像

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

【讨论】:

【参考方案14】:

如果你想要一个纯 CSS 解决方案,这个技巧非常有效 - 使用转换对象。无论是否缓存图像,这也适用于图像:

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 example

Codepen LESS example

【讨论】:

你能举一个例子来说明这如何与图像加载一起工作吗?

以上是关于图像加载时的 jQuery 回调(即使图像被缓存)的主要内容,如果未能解决你的问题,请参考以下文章

检测 jQuery 1.8+ 中的图像加载 - 自弃用以来替代 load()

Javascript/Jquery 加载回调和编写基本函数

为 CSS 动画预加载图像?

用 jquery 替换悬停时的图像:定位问题

通过 jQuery 检测图像加载

使用 jQuery 加载图像并将其附加到 DOM