最近はウェブサイトの制作でjQueryを使わないようにしています。
jQuery無しで実装しようとしたときに意外と困るのがアニメーションでして、大抵のアニメーションはスタイルシートでも再現可能なんですが、slideUpとslideDownの動きがなかなか再現できなくて、時間がかかりました。

今回はVanilla JSとanime.jsライブラリでslideUp、slideDownを再現する方法を備忘録として記載します。

ソースコード

See the Pen Slide toggle with vanilla js and anime.js (without jQuery) by JeyJapan (@st-lite-jn) on CodePen.

実装方法の解説

HTMLは親要素のul要素内のli要素の子要素に、サブメニューとしてさらにul要素が存在し、親要素のli要素に開閉ボタンを設置しています。開閉ボタンには「btn」というclassを設定します。

スタイルシートでサブメニューを表示しないようにしていますが、「display: none;」「 visibility: hidden;」で二重で非表示化しています。

JavaScriptでは「button」classと、定義したサブメニューの開閉ボタンをdocument.querySelectorAllメソッドで取得します。document.querySelectorAllメソッドで取得できるのはNodeListなのでforEachメソッドでElementオブジェクトを取得し、addEventListenerで開閉処理の関数を発火させます。なおIE11ではforEachメソッドでNodeListからElementオブジェクトを取得することはできません。
開閉ボタンをDocument.querySelectorメソッドDocument.getElementByIdメソッドを使って取得すると、Elementオブジェクトが取得できるので、forEachメソッドは不要ですが、それだと1ページ内に複数のボタンが存在していると対応ができません。

const $buttons = document.querySelectorAll(".button");
$buttons.forEach($button => {
	$button.addEventListener("click", slideToggle);
});

開閉処理の関数では、まずクリックした要素を取得し、そのクリックした要素の隣の要素、つまりサブメニューを取得します。

const $subMenu = e.currentTarget.nextElementSibling;

次にif文でクリックした要素に「is-active」クラスが無いか判定して処理を分岐しています。

if(!e.currentTarget.classList.contains("is-active")) 

ボタンに「is-active」クラスがない場合、つまりサブメニューが表示していない場合、
最初にクリックボタンに「is-active」クラスを追加します。
次にサブメニューをdisplay:blockでブロック要素にした上で高さを取得します。
このときスタイルシートでvisibility:hiddenと指定しているので、高さは取得できるけどブラウザからは見えないままです。
そのあとサブメニューの高さ(height)を0にした上で、visibility:visibleで非表示化を解除します。

e.currentTarget.classList.add("is-active");
$subMenu.style.display = "block";
const subMenuHeight = $subMenu.clientHeight;
$subMenu.style.height = 0;
$subMenu.style.visibility = "visible";

高さが動的に変化する処理はanime.jsで行っています。

「keyframes」でアニメーションの開始時と終了時の状態を指定しています。開始時は高さが0の状態で、終了時は先程取得したサブメニューの高さになっている状態を指定しています。
durationでアニメーションをスピードです。500だと0.5秒間でアニメーションを実行します。

easingはアニメーションの変化の仕方を指定します。種類に応じでアニメーションの滑らかさや序盤・終盤でのスピードなどが変わります。easingの種類についてはこちらのサイトが参考になります。

anime({
	targets: $subMenu,
	keyframes:[
		{height: 0},
		{height: `${subMenuHeight}px`}
	],
	duration: 500,
	easing: 'easeInSine',
});

クリックした要素に「is-active」classがある場合、つまりサブメニューが開いている状態の場合は、逆のことを指定することで、slideUpを再現しています。

e.currentTarget.classList.remove("is-active");
const subMenuHeight = $subMenu.clientHeight;
anime({
	targets: $subMenu,
	keyframes:[
		{height: `${subMenuHeight}px`},
		{height: 0}
	],
	duration: 500,
	easing: 'easeInSine',
	complete: () => {
		$subMenu.style.cssText = null;
	}
});

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です




アーカイブ

カテゴリ