web-dev-qa-db-fra.com

Rappel jQuery au chargement de l'image (même lorsque l'image est mise en cache)

Je veux faire:

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

Mais l'événement de chargement ne se déclenche pas lorsque l'image est chargée à partir du cache. Les docs jQuery suggèrent n plugin pour corriger ça, mais ça ne marche pas

276
Tom Lehman

Si la variable src est déjà définie, l'événement est déclenché dans le cas mis en cache, avant même que le gestionnaire d'événements ne soit lié. Pour résoudre ce problème, vous pouvez effectuer une vérification et déclencher l'événement en fonction de .complete, comme suit:

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

Notez le changement de .bind() à .one() afin que le gestionnaire d'événements ne s'exécute pas deux fois.

553
Nick Craver

Puis-je suggérer que vous le rechargiez dans un objet image non DOM? Si elle est mise en cache, cela ne prendra pas de temps et la charge sera toujours déclenchée. S'il n'est pas mis en cache, il se déclenchera lors du chargement de l'image, ce qui devrait être la même heure que le chargement de la version DOM de l'image.

Javascript:

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

Mise à jour (pour gérer plusieurs images et avec une pièce jointe au chargement correctement commandée):

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

Ma solution simple ne nécessite aucun plugin externe et devrait suffire pour les cas courants:

/**
 * 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);
            });
        }
    });
};

utilisez-le comme ceci:

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

par exemple, pour fondre vos images à la charge, vous pouvez faire:

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

Ou bien, si vous préférez une approche de type plug-in 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);

et l'utiliser de cette manière:

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

par exemple:

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

Devez-vous vraiment le faire avec jQuery? Vous pouvez également associer l'événement onload directement à votre image.

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

Il se déclenche chaque fois que l'image est chargée, en cache ou non.

23
Björn

Vous pouvez également utiliser ce code avec un support pour l'erreur de chargement:

$("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();
    }
});
15
Piotr Stępniewski

Je viens d'avoir ce problème moi-même, cherché partout une solution qui n'implique pas de tuer mon cache ou de télécharger un plugin.

Je n'ai pas vu ce fil immédiatement, alors j'ai trouvé quelque chose d'autre qui est une solution intéressante et (je pense) digne de poster ici:

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

J'ai en fait eu cette idée des commentaires ici: http://www.witheringtree.com/2009/05/image-load-event-binding-with-ie-using-jquery/

Je n'ai aucune idée pourquoi cela fonctionne, mais j'ai testé cela sur IE7 et où il s'est cassé avant qu'il ne fonctionne maintenant.

J'espère que ça aide,

Modifier

La réponse acceptée explique en réalité pourquoi:

Si le src est déjà défini, l'événement se déclenche dans le cache casé avant que le gestionnaire d'événements ne soit lié.

13
Sammaye

Une solution que j'ai trouvée https://bugs.chromium.org/p/chromium/issues/detail?id=7731#c12 (Ce code provient directement du commentaire)

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

En utilisant jQuery pour générer une nouvelle image avec la src de l'image et en lui affectant la méthode de chargement directement, la méthode de chargement est appelée avec succès lorsque jQuery a terminé la génération de la nouvelle image. Cela fonctionne pour moi dans IE 8, 9 et 10

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

Une modification de l'exemple de GUS:

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

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

Définissez la source avant et après la charge.

4
Chuck Conway

Ajoutez simplement l'argument src sur une ligne séparée après la définition de img oject. Ceci va piéger IE pour déclencher l'événement lad. C'est moche, mais c'est la solution de contournement la plus simple que j'ai trouvée jusqu'à présent.

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

Je peux vous donner un petit conseil si vous voulez faire comme ceci:

<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>

Si vous faites cela lorsque le navigateur met en cache des images, ce n'est pas un problème, mais le chargement est img, mais le chargement img s'effectue sous une image réelle.

1
Josephy Besim

J'ai eu ce problème avec IE où e.target.width serait indéfini. L'événement de chargement se déclencherait mais je ne pouvais pas obtenir les dimensions de l'image dans IE (chrome + FF travaillé).

Il s'avère que vous devez rechercher e.currentTarget.naturalWidth & e.currentTarget.naturalHeight.

Encore une fois, IE fait les choses à sa manière (plus compliquée).

1
Ali

Vous pouvez résoudre votre problème en utilisant le plugin JAIL qui vous permet également de charger des images en différé (amélioration des performances de la page) et en passant le rappel en paramètre

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

Le HTML devrait ressembler à

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

Si vous voulez une solution CSS pure, cette astuce fonctionne très bien - utilisez l'objet Transformer. Cela fonctionne également avec les images, qu'elles soient mises en cache ou non:

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

exemple de Codepen

exemple de Codepen LESS

0
neoRiley