LoginSignup
2
4

More than 5 years have passed since last update.

【JavaScript】動的に追加したimg要素の表示を待ってから処理する

Last updated at Posted at 2018-11-30

やりたいこと

  • 処理A:append() などで複数のimg要素を追加・表示する。
  • 処理B:Aで追加したimg要素に対して操作を行う。処理Bは、img要素がすべて表示された後に行いたい。

調べたところ、img以外の要素や、動的に追加されたものではないimg要素に対する手法しか見つからなかったのでメモ。

採用した方法

@piouc さんにいただいたコメントより追記です。ありがとうございます。
自分の実装よりスマートなので最終的に使用させていただくこととしました。

1. jQuery.Deferredを使う

function main(){
    // DOMの操作は同期的に行われるため$.whenを利用する必要はない。
    $('最初からある要素').append('追加したいimg要素')

    // 追加されたそれぞれの要素をDeferred化し全てのロードが完了するのを$.whenで待つ
    $.when.apply($, $('追加したimg要素').map(waitForLoading)).then(function(){
        // ロード完了後に行う処理
    })

}
function waitForLoading(index, img){
    var dfd = $.Deferred()

    // img要素のロード完了はimg.completeで取得できます。
    if(img.complete){
        // すでにロードが完了していれば即時resolve。
        dfd.resolve()
    } else {
        // ロードが完了していなかった場合、イベントリスナー登録しロードの完了を待つ
        $(img).on('load', function(){
            resolve()
        })
    }
    return dfd
}

2.jQueryを利用しない場合、async, awaitを使う

async function main(){
    //ここで画像の追加
    await Promise.all(Array.from(document.querySelectorAll('追加したimg要素')).map(waitForLoading))
    // ロード完了後に行う処理
}
function waitForLoading(img){
    return new Promise(resolve => {
        if(img.complete){
            resolve()
        } else {
            img.addEventListener('load', () => resolve())
        }
    })
}

当初やってみたもの

setTimeout()でポーリング+画像の高さが1以上なら表示完了、という力技です。
jQueryの使用を前提としています。

  1. 処理A→処理Bの非同期処理にjQuery.when()を使う。
  2. 処理Bの「img要素が表示された後」の処理にsetTimeout()を使って表示されるまで待つ。
function main() {
    $.when(
        // 処理A
        $('最初からある要素').append('追加したいimg要素');
    ).then(function() {
        loadingCheck();
    });
}

function loadingCheck() {
    var timer;
    var count = 0;

    // 複数でないならループは不要
    $('追加したimg要素').each(function() {
        // 表示されていれば height > 0
        if ($(this).height()) {
            count++;
        }
    });

    // 追加した要素数と、height > 0 の要素数が一致していればすべて表示されている
    if ($('追加したimg要素').length === count) {
        // 処理B
        // $('追加したimg要素')になんらかの処理

        // setTimeout()の停止
        clearTimeout(timer);
    } else {
        // すべて表示されていなければ100ミリ秒(要素数やサイズで調整)待ってもう一度実行
        timer = window.setTimeout(loadingCheck, 100);
    }
}
2
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4