Oteto Blogのロゴ

【Vue.js】アニメーション付きアコーディオンメニューを作る

完成イメージ

detailsタグを使わず、JavaScriptで動的に開閉するアコーディオンメニューです。

コンポーネントとして作り使い回せるので、複数の設置にも対応しています。

実装方法

1. コンポーネント実装

Vue.component("accordion", {
  template: `
    <div class="accordion">
      <div class="title" @click="open()">
        <slot name="title"></slot>
        <transition name="rotate" mode="out-in">
          <i class="fas fa-chevron-up" v-if="isOpen" key="rotate1"></i>
          <i class="fas fa-chevron-down" v-else key="rotate2"></i>
        </transition>
      </div>
      <transition name="open">
        <div class="accordion-content" v-if="isOpen">
          <slot name="content"></slot>
        </div>
      </transition>
    </div>`,
  data: function () {
    return {
      isOpen: false,
    };
  },
  methods: {
    open: function () {
      this.isOpen = !this.isOpen;
    },
  },
});
new Vue({
  el: "#app",
});

2. コンポーネントを呼び出す

<div id="app">
  <accordion>
    <div slot="title">タイトル</div>
    <div class="content" slot="content">
      <p>ここに内容</p>
    </div>
  </accordion>
  <accordion>
    <div slot="title">タイトル</div>
    <div class="content" slot="content">
      <p>ここに内容</p>
    </div>
  </accordion>
  <accordion>
    <div slot="title">タイトル</div>
    <div class="content" slot="content">
      <p>ここに内容</p>
    </div>
  </accordion>
</div>

3. スタイルをあてる

メニューのスタイル

.accordion {
  max-width: 70%;
  margin: 10px auto;
}

.title:hover {
  cursor: pointer;
  opacity: 0.8;
}

.title {
  padding: 15px;
  margin-bottom: 10px;
  background-color: #eee;
  border-radius: 5px;
}

.title > div {
  display: inline-block;
  font-weight: bold;
}

.title i {
  float: right;
  line-height: 1.3;
}

.content {
  padding: 0 15px;
  margin-bottom: 10px;
}

開閉時のアニメーション

.open-enter-active {
  animation: open 0.2s;
}

.open-leave-active {
  animation: open 0.2s linear reverse;
}

@keyframes open {
  0% {
    opacity: 0;
    transform: translateY(-5px);
  }

  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.rotate-enter-active {
  animation: rotate 0.2s linear;
}

@keyframes rotate {
  0% {
    transform: rotate(180deg);
  }
}

あとは適宜デザインを整えてあげれば完成です。