【更新日 :

【脱Jquery】javascriptでスライド系アニメーション(slideDown、slideUp、slideToggle)を実装する

Category: JavaScript

Vanilla JSでスライド系アニメーション(slideDown、slideUp、slideToggle)を実装したサンプルです。
requestAnimationFrameで作成し、イージング編集と、コールバック関数に対応させました。


See the Pen
slideDown slideUp slideToggle Vanilla JS (Easing support)
by Kazuma Sakata (@sakata-kazuma)
on CodePen.


JS

/*
  ■slideUp・slideDown・slideToggleアニメーション処理関数
    animeType: 'slideUp' or 'slideDown' or 'slideToggle'
    elm: 対象要素
    duration: アニメーション時間
    [callBack: コールバック関数(任意)]
*/
function slideAnime(animeType, elm, duration, callBack) {
  'use strict';
  //slideToggle分岐
  if (animeType === 'slideToggle') {
    animeType = getComputedStyle(elm).display === 'none' ? 'slideDown' : 'slideUp';
  }

  //実行判別
  if (
    //slideUp 既に非表示 or 実行中だった場合は処理しない
    (animeType === 'slideUp' && (getComputedStyle(elm).display === 'none' || elm.classList.contains('is-slide-busy')))
    //slideDown 既に表示されている or 実行中だった場合は処理しない
    || (animeType === 'slideDown' && (getComputedStyle(elm).display !== 'none' || elm.classList.contains('is-slide-busy')))
    //有効なキーワードではない場合も処理しない
    || (animeType !== 'slideUp' && animeType !== 'slideDown')
  ) {
    return false;
  }

  //実行中class追加
  elm.classList.add('is-slide-busy');

  /*
    イージング設定
      ・参考サイト
        https://github.com/danro/jquery-easing/blob/master/jquery.easing.js
        https://noze.space/archives/432#index-3
    「t:アニメーションの経過時間」「b:始点」「c:変化量」「d:変化にかける時間」
  */
  function easing(t, b, c, d) {
    return c * (0.5 - Math.cos((t / d) * Math.PI) / 2) + b;
  }

  //初期設定
  elm.style.overflow = 'hidden';
  //初期設定 アニメーション分岐
  let slideFunc;
  if(animeType === 'slideDown') {
    //初期設定 要素を表示
    elm.style.display = 'block';

    //アニメーション関数設定
    slideFunc = function(elapsedTime,duration,heightVal) {
      Object.keys(heightVal).forEach(function(key) {
        //easing(「アニメーションの経過時間」,「始点」,「変化量」,「変化にかける時間」)
        elm.style[key] = easing(elapsedTime, 0, heightVal[key], duration) + 'px';
      });
    }

  } else if(animeType === 'slideUp') {
    //アニメーション関数設定
    slideFunc = function(elapsedTime,duration,heightVal) {
      Object.keys(heightVal).forEach(function(key) {
        elm.style[key] = (heightVal[key] - easing(elapsedTime, 0, heightVal[key], duration)) + 'px';
      });
    }
  }

  //高さ関連のstyleを取得
  const styles = getComputedStyle(elm);
  const heightVal = {
    height: elm.getBoundingClientRect().height,
    marginTop: parseFloat(styles.marginTop),
    marginBottom: parseFloat(styles.marginBottom),
    paddingTop: parseFloat(styles.paddingTop),
    paddingBottom: parseFloat(styles.paddingBottom)
  };

  //有効なstyleのみ取り出し
  Object.keys(heightVal).forEach(function(key) {
    //値が0の場合は削除する
    if(heightVal[key] ===  0) {
      delete heightVal[key];
    }
  });

  //有効なプロパティが1件もない場合は処理を終了
  if(Object.keys(heightVal).length === 0) {
    return false;
  }

  //アニメーション開始時間
  const start = new Date();
  function mainAnime() {
    //イベント発生後の経過時間
    let elapsedTime = new Date() - start;

    //アニメーション終了処理
    if (elapsedTime > duration) {
      //実行中class削除
      elm.classList.remove('is-slide-busy');
      //slideUpの場合は要素を非表示
      if(animeType === 'slideUp') {
        elm.style.display = 'none';
      }

      //アニメーション用styleを削除
      elm.style.overflow = '';
      Object.keys(heightVal).forEach(function(key) {
        elm.style[key] = '';
      });

      //コールバック関数が設定されていたら呼び出す
      if(typeof callBack === 'function') {
        callBack();
      }

      //処理を終了
      return false;
    }

    //アニメーション実行処理
    slideFunc(elapsedTime,duration,heightVal);
    requestAnimationFrame(mainAnime);
  }

  //アニメーション初回呼び出し
  requestAnimationFrame(mainAnime);
}

関数の呼び出し

任意の場所で以下を実行し関数を呼び出してください。

//slideDown
slideAnime('slideDown', 対象要素, アニメーション時間 [, コールバック関数(任意)]);

//slideUp
slideAnime('slideUp', 対象要素, アニメーション時間 [, コールバック関数(任意)]);

//slideToggle
slideAnime('slideToggle', 対象要素, アニメーション時間 [, コールバック関数(任意)]);

動作サンプル

HTML

<button id="js-slide-down">fadeIn</button>
<div class="js-slide-down-elm">slideDown要素</div>

<button id="js-slide-up">slideUp</button>
<div class="js-slide-up-elm">slideUp要素</div>

<button id="js-slide-toggle">slideToggle</button>
<div class="js-slide-toggle-elm">slideToggle要素</div>

CSS

/* slideDown用設定 */
.js-slide-down-elm {
  display: none;
}

JS

//slideDownテスト
const slideDownElm = document.querySelector('.js-slide-down-elm');
document.getElementById('js-slide-down').addEventListener('click', function() {
  /*
    ・slideDown呼び出し
      slideAnime('slideDown', 対象要素, アニメーション時間 [, コールバック関数(任意)]);
  */
  slideAnime('slideDown', slideDownElm, 400, function() {
    console.log('slideDown終了');
  });
});

//slideUpテスト
const slideUpElm = document.querySelector('.js-slide-up-elm');
document.getElementById('js-slide-up').addEventListener('click', function() {
  /*
    ・slideUp呼び出し
      slideAnime('slideUp', 対象要素, アニメーション時間 [, コールバック関数(任意)]);
  */
  slideAnime('slideUp', slideUpElm, 400, function() {
    console.log('slideUp終了');
  });
});

//slideToggleテスト
const slideToggleElm = document.querySelector('.js-slide-toggle-elm');
document.getElementById('js-slide-toggle').addEventListener('click', function() {
  /*
    ・slideToggle呼び出し
      slideAnime('slideToggle', 対象要素, アニメーション時間 [, コールバック関数(任意)]);
  */
  slideAnime('slideToggle', slideToggleElm, 400, function() {
    console.log('slideToggle終了');
  });
});

イージング設定や処理速度、コールバック関数(任意)はサイトに合わせて編集してください。

Category : JavaScript