🐕
jQueryのslideToggleは偉大だ、という話
jQueryのslideToggleを使えばすぐできる、アニメーションでスライドするアコーディオンの実装。
それを、素のJavaScriptを使って書き換えてみたらなかなか大変だった、という話です。
やりたかったのは、以下。
HTMLの構造
HTML
<div>
<article class="js_accordion">
<p>にゃーん</p>
</article>
<article class="js_accordion">
<p>わんわん</p>
</article>
<div class="accordion_btn_wrap">
<button class="js_accordion_btn"></button>
</div>
</div>
jQueryで書くと数行
jQuery
$(function(){
$('.js_accordion_btn').on('click', function(){
let $accordions = $(this).parents('.accordion_btn_wrap').siblings('.js_accordion');
$accordions.slideToggle();
});
});
素のJavaScriptで書き直した
JavaScript
/* 素のJavaScriptでの、アニメーションアコーディオン実装 */
// DOMの構築後に実行
document.addEventListener('DOMContentLoaded', function(){
// 開閉ボタン
const slideToggleBtns = document.querySelectorAll(".js_accordion_btn");
slideToggleBtns.forEach(function(slideToggleBtn) {
// 各ボタンにイベントを付与
slideToggleBtn.addEventListener("click", (event) => {
// ボタンから辿って、スライドさせたい要素を取得
let slides = event.currentTarget.parentNode.parentNode.getElementsByClassName('js_accordion');
// 配列に変換
let slides_array = Array.from(slides);
// 配列の要素を一つずつslideToggle関数で開閉
slides_array.forEach(function(el) {
slideToggle(el, 300);
});
});
});
});
// slideUp
const slideUp = (el, duration = 300) => {
el.style.height = el.offsetHeight + "px";
el.offsetHeight;
el.style.transitionProperty = "height, margin, padding";
el.style.transitionDuration = duration + "ms";
el.style.transitionTimingFunction = "ease";
el.style.overflow = "hidden";
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
el.style.marginTop = 0;
el.style.marginBottom = 0;
setTimeout(() => {
el.style.display = "none";
el.style.removeProperty("height");
el.style.removeProperty("padding-top");
el.style.removeProperty("padding-bottom");
el.style.removeProperty("margin-top");
el.style.removeProperty("margin-bottom");
el.style.removeProperty("overflow");
el.style.removeProperty("transition-duration");
el.style.removeProperty("transition-property");
el.style.removeProperty("transition-timing-function");
}, duration);
};
// slideDown
const slideDown = (el, duration = 300) => {
el.style.removeProperty("display");
let display = window.getComputedStyle(el).display;
if (display === "none") {
display = "block";
}
el.style.display = display;
let height = el.offsetHeight;
el.style.overflow = "hidden";
el.style.height = 0;
el.style.paddingTop = 0;
el.style.paddingBottom = 0;
el.style.marginTop = 0;
el.style.marginBottom = 0;
el.offsetHeight;
el.style.transitionProperty = "height, margin, padding";
el.style.transitionDuration = duration + "ms";
el.style.transitionTimingFunction = "ease";
el.style.height = height + "px";
el.style.removeProperty("padding-top");
el.style.removeProperty("padding-bottom");
el.style.removeProperty("margin-top");
el.style.removeProperty("margin-bottom");
setTimeout(() => {
el.style.removeProperty("height");
el.style.removeProperty("overflow");
el.style.removeProperty("transition-duration");
el.style.removeProperty("transition-property");
el.style.removeProperty("transition-timing-function");
}, duration);
};
// slideToggle
const slideToggle = (el, duration = 300) => {
if (window.getComputedStyle(el).display === "none") {
return slideDown(el, duration);
} else {
return slideUp(el, duration);
}
};
おわかりいただけただろうか
jQueryのslideToggle、すごくない?
自分が知る限りだと、jQueryのslideToggleを簡単に代替する手法は見当たりませんでした。特に、スライド内容の高さが決まっていない場合ですね。
cssのtransition
でアニメーションさせるにも、max-height
を決め打ちする必要があるので、高さがマチマチの場合は使えません。
まあ昨今は、DOM操作をjsでやること自体がレトロなのかもしれませんが、やる必要があるときにはjQuery御大は今でもたいへん便利だなと思いました。
個人的希望としては、ゆくゆくは<details>
要素にcssでアニメーションを指定できるようになってほしいです。
ではまた。
参考文献
なお、slideToggle関数自体は、こちらの記事を参考にいたしました。
大変ありがたかったです m(_ _)m
追記
bootstrapの機能で、簡単にできることが判明😆
Discussion