JavaScript

画像(IMG要素)の読み込み後(loadイベント)の処理が動かない対策

jQueryを使って、画像(IMG要素)にイベントリスナーを設置したら動かなかったので対策したメモです。今まで気づかなかったのなんでかなぁ、とちょっと不思議でしたが単に物忘れだと思うので備忘録として書きます。

一定の間隔で複数の画像をスライドさせるようなコードをチャチャッと書いてみたものの、各画像が大きそうだったので「次の画像を表示前に読み込み開始させるか」と思ってIMGタグのロードイベントを取ろうと思ったら、Safariではうまく動いていたのにChromeFirefoxではうまく動きませんでした。

$('<img src="img.jpg">').on('load', function(){
  alert('読み込みました。');
});

こうなった場合、jQueryを必要としない他の書き方も同様に動かないです。とにかく画像のロードイベントが始まっていないなというのは容易に想像が付くと思います。

// 動かない例

var img = new Image(); // document.createElement('img') でもいっしょ
img.src = "img.jpg";

// onload
img.onload = function () {
  alert('読み込みました。');
}

// addEventListener
img.addEventListener('load', function(){
  alert('読み込みました。');
});

とりあえず「原因はどうでもいいのでとにかく動くヤツ頼む」と思ってググったんですが、海外のフォーラムも含めてネット上にある解決策を試してもうまくいきませんでした。

その中に「キャッシュが効いてると(すでに読み込み済み)ロードイベントが発生しないので.completeを見るんだよ、カッカッカ」的なコードがあったんですが残念ながらハズレ、こちらの環境ではキャッシュに関わらずこの値は偽のままでうまく動作しませんでした。

$("img").one("load", function() {
   //do stuff
}).each(function() {
   if(this.complete || /*for IE 10-*/ $(this).height() > 0)
     $(this).load();
});
jQuery .load() not working on my image - Stack Overflow

解決

で、上のコードをヒントに「どっちみちロードイベントを一度発生させる」ように修正することで解決しました。お尻に.load()をくっつけて必ずロードが始まるようにします。

$('<img src="img.jpg">').one('load', function(){
  alert('読み込みました。');
}).load();

気をつける点は、イベントにバインドさせるために.on().bind().load()ではなく、一度だけ実行する.one()を使うところでしょうか。これによって、今まで動いていたブラウザで2回実行しなくて済みます。


これで無事に画像の読み込み後の処理を実行することができるようになりました。ドキュメント内の<IMG>要素だけでなく、CSSによる大きな背景画像を先に読み込むような場合にも便利だと思います。

以上、jQueryで、画像のロードイベントのコールバックが動かない件の対策でした。