[jQuery再現]JavaScriptとCSSで作るSlideToggleメソッドっぽいもの

素のJavaScriptでjQueryのトグルメソッドを再現します。
アニメーションはCSSで行うので処理も軽いかも…?

コードの利用は自己責任でお願いします。

サンプル

target1
スライドトグル実装!
const toggleBtn1 = document.querySelector('.toggle-btn1');
const targetEl1 = document.querySelector('.target1');

toggleBtn1.addEventListener('click', () => {
    slideToggle(targetEl1);
});
Target2
スピードも変えられる!
const toggelBtn2 = document.querySelector('.toggle-btn2');
const targetEl2 = document.querySelector('.target2');

toggelBtn2.addEventListener('click', () => {
    slideToggle(targetEl2, 2000);
});

使い方

slideToggleのターゲットにする要素全てに「slide-toggle」クラスを付与します。

後は、関数「slideToggle(ターゲット, 時間)」でメソッドの様に利用できます。

「slide-toggle」 を付与した要素にmargin、paddingが設定されているとうまく動作しません。設定する場合はその中に子要素を作り、そこに設定しましょう。

画像などをwidth100%に設定する場合、要素全体をposition:relativeで囲うなどが必要です。

CSS

.slide-toggle {
    position: absolute;
    visibility: hidden;
    overflow: hidden;
}

.slide-toggle.st-open {
    position: relative;
    visibility: visible;
}

JavaScript

const slideSpeed = '400';
const slideToggleElement = document.querySelectorAll('.slide-toggle');

slideToggleElement.forEach(el => {
    el.addEventListener('transitionend', function () {
        this.style.height = 'auto';
        this.classList.remove('st-moving');
        if (this.classList.contains('st-close')) {
            this.style.transition = '0s';
            this.classList.remove('st-close');
            this.classList.remove('st-open');
        }
    });
});

function slideToggle(target, speed) {
    if (!speed) {
        speed = slideSpeed;
    }
    target.style.transition = speed + 'ms';
    if (target.classList.contains('st-moving') === false) {
        target.classList.add('st-moving');
        height = target.clientHeight;
        if (target.classList.contains('st-open')) {
            target.classList.add('st-close');
            target.style.height = height + 'px';
            setTimeout(function () {
                target.style.height = 0;
            });
        } else {
            target.style.height = 0;
            target.classList.add('st-open');
            setTimeout(function () {
                target.style.height = height + 'px';
            });
        }
    }
}

簡単な解説

const slideSpeed = '400';
const slideToggleElement = document.querySelectorAll('.slide-toggle');
  • 基本スピードと要素を取得
function slideToggle(target, speed) {
    if (target.classList.contains('st-moving') === false) {
        if (!speed) {
            speed = slideSpeed;
        }
        target.style.transition = speed + 'ms';
        target.classList.add('st-moving');
        height = target.clientHeight;
        if (target.classList.contains('st-open')) {
            target.classList.add('st-close');
            target.style.height = height + 'px';
            setTimeout(function () {
                target.style.height = 0;
            });
        } else {
            target.style.height = 0;
            target.classList.add('st-open');
            setTimeout(function () {
                target.style.height = height + 'px';
            });
        }
    }
}
  • 「st-moving」が付いている場合は何もしない。
    動作開始で付与、動作完了で取るクラス。
    アニメーション中に動作しないようにするため。
  • 速度が設定されているかどうかを確認しtransitionに設定
  • 現在の高さを変数に入れてから開閉で条件分岐
  • 開く時はheightを0にし「st-open」を付与
    その後変数に保存した高さを設定することでCSSでアニメーション
    (高さ取得のタイミングでは要素はabsoluteのため取得できる)
  • 閉じるときは「st-close」を付与し変数heightを付与
    その後高さ0を指定することでCSSでアニメーション
slideToggleElement.forEach(el => {
    el.addEventListener('transitionend', function () {
        this.style.height = 'auto';
        this.classList.remove('st-moving');
        if (this.classList.contains('st-close')) {
            this.style.transition = '0s';
            this.classList.remove('st-close');
            this.classList.remove('st-open');
        }
    });
});

各要素にトランジションが終わった時に以下の処理

  • heightをautoに(レスポンシブ時に固定されないよう)
  • 「st-moving」を外す

さらに「st-close」がある場合(閉じる時のクラス)

  • transitionを0に(0にしないと次回アニメーションしてしまう)
  • 「st-close」「st-open」を外す

完成!

以上で完成です。

次回以降でこれを応用したQ&Aを作ります。

タイトルとURLをコピーしました