1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

素のJavaScriptでDOM要素をフェードイン/アウトさせる

Last updated at Posted at 2023-08-15

はじめに

この記事ではjQueryのメソッドの一つである fadeIn()fadeOut() をVanillaJS(素のJS)で実現するソリューションを紹介します。

背景

  • 筆者はここ数年jQueryからVanillaJSへの移行をおこなっている。
  • 筆者はjQueryのメソッドである fadeIn()fadeOut() を多用している。

課題

  • jQueryの fadeIn()fadeOut() に該当するメソッドがVanillaJSには存在しない。
  • 移行にあたり使いまわせるコードを残しておきたい。

仕様

できるだけ jQueryの fadeIn() & fadeOut() に近い仕様で実装したいと考えた。

  1. フェードイン/アウトをさせるDOM要素を指定する。
  2. フェードイン/アウトの時間をミリ秒で指定する。
  3. 非同期処理を実現する。
    • 例えば、フェードイン/アウトのアニメーションの終了を待ってから次の処理を行うことができる。
    • jQueryではコールバック関数を用いていたが、ここでは非同期処理(Promise or async & awaitを採用した。)

fadeIn()

fadeIn(element, duration?, display?);
引数 説明
element   HTMLElement フェードインしたいDOM要素を指定
duration number アニメーション時間をミリ秒で指定
display String 表示時のdisplayプロパティを指定1

fadeOut()

fadeOut(element, duration?);
引数 説明
element   HTMLElement フェードアウトしたいDOM要素を指定
duration number アニメーション時間をミリ秒で指定

コード

const delay = 40; // fps=25

function fadeIn() {
    return new Promise(async (resolve, reject) => {
        if (arguments.length > 0) {
            const elem = arguments[0];
            if (elem.style.display === 'none' || elem.style.display === '') {
                const duration = arguments.length === 2 ? arguments[1] : 500;
                const display = arguments.length === 3 ? arguments[2] : 'block';
                elem.style.display = display;

                const coef = 1 / (duration / delay);
                elem.style.opacity = 0;
                var opacity = Number(elem.style.opacity);
                var animation = setInterval(() => {
                    opacity += coef;
                    elem.style.opacity = opacity;
                    if (opacity >= 1) {
                        clearInterval(animation);
                        resolve(true);
                    }
                }, delay);
            }
        }
    });
}

function fadeOut() {
    return new Promise(async (resolve, reject) => {
        if (arguments.length > 0) {
            const elem = arguments[0];
            if (elem.style.display !== 'none') {
                const duration = arguments.length === 2 ? arguments[1] : 500;

                const coef = 1 / (duration / delay);
                elem.style.opacity = 1.0;
                var opacity = Number(elem.style.opacity);
                var animation = setInterval(() => {
                    opacity -= coef;
                    elem.style.opacity = opacity;
                    if (opacity <= 0) {
                        elem.style.display = 'none';
                        clearInterval(animation);
                        resolve(true);
                    }
                }, delay);
            }
        }
    });
}

非同期処理として実装する

return new Promise(async (resolve, reject) => {
    /* ここに処理を書く */
});

引数のチェック

// 引数は必ず一つ以上
if (arguments.length > 0) {
    // 第1引数はDOM要素
    const elem = arguments[0];
    // 第2引数はデュレーション時間
    const duration = arguments.length === 2 ? arguments[1] : 500;
    // 第3引数はdisplayプロパティ (フェードインのみ)
    const display = arguments.length === 3 ? arguments[2] : 'block';
}

フェード処理

フェードイン

// 現在表示されていないことを確認
if (elem.style.display === 'none' || elem.style.display === '') {

    // 表示モードにしたうえで、不透明度を0にする。
    elem.style.display = display;
    elem.style.opacity = 0;

    // 不透明度
    // elem.style.opacityはString型なので、数値として扱うためにnumber型にキャストする必要がある。
    // 初期値は0
    var opacity = Number(elem.style.opacity);

    // setIntervalが実行されるたびに不透明度に加算する定数
    const coef = 1 / (duration / delay);

    // setIntervalによって徐々に不透明度を1に近づける。
    var animation = setInterval(() => {
        opacity += coef;
        elem.style.opacity = opacity;

        // 終了条件 : 不透明度が1以上
        if (opacity >= 1) {
            clearInterval(animation);
            resolve(true);
        }
    }, delay);
}

フェードアウト

// 現在表示されていることを確認
if (elem.style.display !== 'none') {

    // 不透明度を1にする
    elem.style.opacity = 1.0;
    var opacity = Number(elem.style.opacity);

    // setIntervalが実行されるたびに不透明度に減算する定数
    const coef = 1 / (duration / delay);

    // setIntervalによって徐々に不透明度を0に近づける。
    var animation = setInterval(() => {
        opacity -= coef;
        elem.style.opacity = opacity;

        // 終了条件 : 不透明度が0以下
        if (opacity <= 0) {
            elem.style.display = 'none';
            clearInterval(animation);
            resolve(true);
        }
    }, delay);
}

使い方

const elem = document.querySelector("#elem");
const duration = 600;
fadeIn(elem, duration, 'block');
fadeOut(elem, duration);
console.log("done");

非同期処理 (promise)

const elem = document.querySelector("#elem");
const duration = 600;
fadeIn(elem, duration, 'block')
    .then(() => {
        fadeOut(elem, duration)
            .then(() => {
                console.log("done");
            });      
    });

非同期処理 (async/await)

const elem = document.querySelector("#elem");
const duration = 600;
await fadeIn(elem, duration, 'block');
await fadeOut(elem, duration);
console.log("done");

ライブラリ化

以上の処理をライブラリ化しました。(TypeScript対応済み)

インストール

  • JavaScript : ここから fadeIOnu.js をダウンロード

  • TypeScript

    npm i https://github.com/tomoya-onuki/fadeIOnu.js/
    
  1. CSSのプロパティである displayについては公式のドキュメントを参考しにしてください。https://developer.mozilla.org/ja/docs/Web/CSS/display

1
2
0

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?