こんにちわ。 今日は前回の続き(「絶対フォント感」を身につけようとすると新たな扉が開く話 - その1 - http://lab.astamuse.co.jp/entry/2018/06/06/131745)を書こうと思ってたのですが、 アクセス数がかなり少かった(;;)ので一旦お休みしてフロントエンドっぽい事書いていこうと思います。
概要
vueでやるとAPIやdataリストにタイトルや本文を入れたくなりますが、今回は以下の要望を満たすものを作っていこうと思います。
- アコーディオンの中身(タイトルや本文)はhtml側で制御したい
それでは早速Vue.jsでAccordionを作ってみるく♡
step.1 下準備(html、css)
今回デザインはこんな感じで作っていきます。
See the Pen vue-accordion - html,css by 35n139e (@35n139e) on CodePen.
step.2 開閉機能を実装する
ひとまずアコーディオンの最低限の要素を実装していきます。
- ボタンを押す
- ターゲットコンテンツの開閉(toggle)
<div id="app"> <js-accordion></js-accordion> </div>
Vue.component('js-accordion', { template: ` <div class="js-accordion" v-cloak> <button class="js-accordion--trigger" type="button" :class="{ '_state-open': isOpened }" @click="accordionToggle()"> アコーディオン </button> <div class="js-accordion--target" :class="{ '_state-open': isOpened }" v-if="isOpened"> <div class="js-accordion--body"> アコーディオンの中身 </div> </div> </div> `, data() { return { isOpened: false }; }, methods: { accordionToggle: function(){ this.isOpened = !this.isOpened; }, } }); new Vue({ el: '#app' });
See the Pen vue-accordion - step2 by 35n139e (@35n139e) on CodePen.
step.3 タイトル・本文をhtml側で制御出来るようにする
冒頭でも書いたように今回のアコーディオンの要望は「アコーディオンの中身(タイトルや本文)はhtml側で制御したい」でしたので、'slot'や'props'を用いてそれを実現していきます。
slotが複数あるので、slotにnameを付けて紐づけしていきます。
<div id="app"> <js-accordion> <div slot="title">アコーディオン1</div> <div class="js-accordion--body" slot="body"> <p>アコーディオン1の中身</p> <p>アコーディオン1の中身</p> <p>アコーディオン1の中身</p> </div> </js-accordion>
Vue.component('js-accordion', { template: ` <div class="js-accordion" v-cloak> <button class="js-accordion--trigger" type="button" :class="{ '_state-open': isOpened }" @click="accordionToggle()"> <slot name="title"></slot> </button> <div class="js-accordion--target" :class="{ '_state-open': isOpened }" v-if="isOpened"> <slot name="body"></slot> </div> </div> `
<div id="app"> <js-accordion title="アコーディオン1"> <div class="js-accordion--body"> <p>アコーディオン1の中身</p> <p>アコーディオン1の中身</p> <p>アコーディオン1の中身</p> </div> </js-accordion>
Vue.component('js-accordion', { template: ` <div class="js-accordion" v-cloak> <button class="js-accordion--trigger" type="button" :class="{ '_state-open': isOpened }" @click="accordionToggle()"> {{this.title}} </button> <div class="js-accordion--target" :class="{ '_state-open': isOpened }" v-if="isOpened"> <slot></slot> </div> </div> ` props: { title: { required: true }, },ほんの少しですがマークアップダイエットが出来ました。
See the Pen vue-accordion - step3 by 35n139e (@35n139e) on CodePen.
fin アニメーションをつけて完成
最後に開閉時のアニメーションを付けていきましょう
vueでanimationをつけるときは<transition>
を使っていきます。
高さの伸縮は、cssだけでも表現可能なのですが制約があるので、今回はvueで開閉後の高さを取得してcssのtransition
でアニメーションさせて、
FadeInOutはCSS アニメーションで表現していきます。
まず、<transition>
にイベントタイミングを設定していきます。
(詳しくはこちらhttps://jp.vuejs.org/v2/guide/transitions.html#JavaScript-%E3%83%95%E3%83%83%E3%82%AF)
// 閉じた状態の高さは el.style.height = '0' // 開いた状態の高さは el.style.height = el.scrollHeight + 'px';
jqueryのslideDown()
ように高速でdomをいじるのではなく、
0px →開いた状態の高さpxをtransition: height 0.4s ease-in-out
でアニメーションさせてあげれば表現出来ます。
(勿論jqueryでもこの方法は可能)
.js-accordion{ &--target{ transition: height 0.4s ease-in-out; } // (略) &-enter-active{ animation-duration: 1s; animation-fill-mode: both; animation-name: js-accordion--anime__opend; } &-leave-active{ animation-duration: 1s; animation-fill-mode: both; animation-name: js-accordion--anime__closed; } } @keyframes js-accordion--anime__opend { 0% { opacity: 0; } 100% { opacity: 1; } } @keyframes js-accordion--anime__closed { 0% { opacity: 1; } 100% { opacity: 0; } }
// (略) template: ` (略) <transition name="js-accordion" @before-enter="beforeEnter" @enter="enter" @before-leave="beforeLeave" @leave="leave"> <div class="js-accordion--target" :class="{ '_state-open': isOpened }" v-if="isOpened"> <slot name="body"></slot> </div> </transition> `, // (略) method:{ beforeEnter: function(el) { el.style.height = '0'; }, enter: function(el) { el.style.height = el.scrollHeight + 'px'; }, beforeLeave: function(el) { el.style.height = el.scrollHeight + 'px'; }, leave: function(el) { el.style.height = '0'; }
Vue.jsでAccordion、完成です!
See the Pen vue-accordion - fin by 35n139e (@35n139e) on CodePen.
駆け足でしたが、以上で終わります。
今年はvue周りの書籍が複数出版されて更にVue.jsの普及が進みそうでうれしいですね。
- 基礎から学ぶ Vue.js https://www.amazon.co.jp/dp/B07D9BYHMZ/
- Vue.js入門 基礎から実践アプリケーション開発まで https://www.amazon.co.jp/dp/B07J6FP6NQ/ref=cm_sw_r_tw_dp_U_x_Q1bXBbWXR8E
- Nuxt.jsビギナーズガイド https://www.amazon.co.jp/dp/4863542569/ref=cm_sw_r_tw_dp_U_x_J2bXBbB86RMJ