vue.jsで開閉式のメニューを作る

こんにちは、フロントエンドエンジニアのてりーです。

はじめに

久々のVue.jsですが、今回は開閉式のメニューをコンポーネントで作っていきたいと思います。
下記の感じのクリックすると開いたり、閉じたりする感じのコンポーネントですね。

アコーディオンって呼ばれ方をする場合もあります。

 

 

vuetifyのv-selectの使い方は知りたい方はこちらの記事を読んで下さい

https://terrblog.com/v-select%e3%81%a7%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e3%82%92%e5%8f%96%e5%be%97%e3%81%99%e3%82%8b/

 

実装パート

 

HTML部分

 

以下のようなソースコードになります。
数字を振ってあるので、順番に解説していきます。

<template>   <div class="profile-accordion">  //①見えている「てりー」の部分に@clickイベント//     <div class="profile-title" @click="toggle">       <p>てりー</p>       <div class="base">         <span class="down-arrow"></span>       </div>     </div>  //②transitionを使って動きを何パターンか指定//     <transition       v-on:before-enter="onBeforeEnter"       v-on:enter="onEnter"       v-on:bofore-leave="onBeforeLeave"       v-on:leave="onLeave"     >  //③v-showでクリック時のみ見えるようにする//       <div v-show="show" class="accordion-wrapper">         <div class="accordion-title -ly_contents">           <p>メニュー</p>         </div>         <div class="accordion-contents -ly_contents">           <ul>             <li class="contents-list">基本情報</li>             <li class="contents-list">パスワード</li>             <li class="contents-list">メールアドレス</li>           </ul>         </div>         <div class="bar -ly_contents"></div>         <div class="accrodion-footer -ly_contents">           <p>サインアウト</p>         </div>       </div>     </transition>   </div> </template> 

①@clickイベント

@clickはv-onの省略形です。
v-onで見えている部分をクリックするとtoggleというイベントが発火するようにしています。
toggleの処理はscriptの部分で書きます。

②transitionを指定

transitionでイベント時の動き方を指定しています。
transitionでは動きに対して、そのフェイズ毎に状態を指定することができます。

今回は以下の4パターンで指定しています。
具体的な状態はscriptにて記載しています。

 //要素の表示前 v-on:before-enter="onBeforeEnter"  //要素の表示中  v-on:enter="onEnter"  //要素を閉じる前  v-on:bofore-leave="onBeforeLeave"  //要素を閉じ中  v-on:leave="onLeave"

③v-showにて表示・非表示切り替え

v-showで”show”状態なら括った要素を表示できるようにしています。
showがtrueかfalseかは@clickイベントのtoggleにて切り替えられるようにしています。

script部分

<script> export default {   name: "HelloWorld",  //①showの初期状態はfalseで閉じておく   data() {     return {       show: false     };   },   methods: { //②toggleにてshowを切り替え     toggle: function() {       this.show = !this.show;     },  //③transitionの各々での高さを指定     onBeforeEnter: function(el) {       el.style.height = 0;     },     onEnter: function(el) {       el.style.height = "182px";     },     onBeforeLeave: function(el) {       el.style.height = "182px";     },     onLeave: function(el) {       el.style.height = 0;     }   } }; </script>

①showの初期値

showの初期値はfalseで指定指定して、閉じています。

②toggleイベント

toggleイベントの処理に、showの切り替えを入れています。
これにより、クリックする度に表示・非表示が切り替わります。

③transitionの値の指定

先ほど出てきたtransitionの各フェイズでの具体的な値を指定しています。
今回は開いている時に高さが出て、閉じている時は高さ0になるようにしています。

css部分

style scoped> .profile-accordion {   height: 210px;   width: 144px; } .profile-title {   margin-left: 50px;   height: 20px;   display: flex; }  .profile-title > p {   margin: 0;   height: 20px;   width: 56px;   color: #354052;   font-family: "Noto Sans CJK JP";   font-size: 14px;   letter-spacing: 0;   line-height: 20px; } .profile-title > .base {   margin-top: 13px;   margin-left: 6px; }  .profile-title > .base > span {   width: 0;   height: 0;    border-style: solid;   border-width: 6px 4px 0 4px;   border-color: #C5D0DE transparent transparent transparent; }  .accordion-wrapper {   position: relative;   margin-top: 20px;   margin-right: 80px;   height: 182px;   width: 140px;   background-color: #FFFFFF;   box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.3); }  .accordion-wrapper::before {   content: "";   position: absolute;   display: block;   width: 0;   height: 0;   left: 100px;   top: -10px;   border-right: 10px solid transparent;   border-bottom: 10px solid #C5D0DE;   border-left: 10px solid transparent; }  .accordion-wrapper::after {   content: "";   position: absolute;   display: block;   width: 0;   height: 0;   left: 100px;   top: -8px;   border-right: 10px solid transparent;   border-bottom: 10px solid #FFFFFF;   border-left: 10px solid transparent; }  .-ly_contents {   margin-left: 16px; }  .accordion-title {   padding: 20px 0 16px; } .accordion-title > p {   color: #354052;   font-family: "Noto Sans CJK JP";   font-size: 14px;   letter-spacing: 0;   line-height: 18px;   padding: 0;   margin: 0;   text-align: left; } .accordion-contents {   display: block;   padding: 0; }  .accordion-contents > ul {   text-align: left;   padding: 0;   margin: 0 0 10px; }  .accordion-contents > ul > li {   color: #354052;   font-family: "Noto Sans CJK JP";   font-size: 12px;   letter-spacing: 0;   line-height: 18px;   list-style: none;   margin-bottom: 8px; }  .bar {   height: 0.99px;   width: 108px;   background-color: #E0E6EF; } .accrodion-footer {   padding: 0;   text-align: left; }  .accrodion-footer > p {   color: #354052;   font-family: "Noto Sans CJK JP";   font-size: 12px;   letter-spacing: 0;   line-height: 18px;   margin-bottom: 16px; } </style> 

cssは形は作りましたが、汚いのであまり参考にしない方が良いです!笑
時間があるときに修正します。