3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

アコーディオンを自作する

Last updated at Posted at 2019-12-08

始めに

アコーディオンはjQueryだとslideToggleが優秀でこれを使えばいいですが、Vue.jsとかではどうやったらいいか悩むことがあるかもしれません。
幸いVue.jsにはvue-slide-up-downというライブラリがあるのでこれを使えばいいかもしれませんが、もし自作をする場合はどうやって実装するかをまとめたいと思います。
(僕も最初は知らなくて自作してました・・・)

実装方法

開く処理

前提として、アコーディオンの高さは0pxにして、overflow: hiddenも設定しておきます。これをしないと中身が見えちゃいますので(汗)。
この状態で以下の手順を踏んで開くアニメーションをします。

  1. コンテンツの高さ(図ではelContent)を取得して、その値を親にセットする
  2. CSS transitionで目標の値までアニメーションする
  3. アニメーション終了後スタイルをリセットする(リセットしないと開いた後にサイズが変更しても調整されなくなってしまいます)

0bf0edc2-a0fc-4043-b697-d9b31354bc14.jpg

閉じる処理

閉じる場合は以下のような手順を踏みます。ワンテンポ置くというのはVue.jsのtransitionと同じ発想で、activeに初期値をセットし、toで目標の値をセットするやり方と一緒です。

  1. アコーディオン全体の今の高さを取得し、その値をセットする。その後ワンテンポ置いてから0pxをセットする。
  2. CSS transitionで0pxに向かってアニメーションされる
  3. 閉じた場合はスタイルのリセットは行わない(リセットすると中身が見えてしまうため)
    f0ff08f0-41c0-47bf-a650-5e92738922f3.jpg

まとめ

まとめると、以下のようなコードになります。
コンポーネント化しているので、開閉のタイミングはwatchで監視しています。

const Accordion = Vue.extend({
  props: {
    isOpen: Boolean,
  },
  data() {
    return {
      heightStyle: this.$props.isOpen ? '' : '0px',
      isOverflow: !this.$props.isOpen,
    };
  },
  watch: {
    // 開閉フラグの監視
    '$props.isOpen'(isOpen) {
      this.$data.isOverflow = true;
      // 現在の高さを設定
      this.$data.heightStyle = `${this.$refs.elAccordion.clientHeight}px`;
      // ワンテンポおいてから目標の高さを設定するが、$nextTickだとうまくいかないのでsetTimeoutに変更
      window.setTimeout(() => {
        this.$data.heightStyle = isOpen ? `${this.$refs.elContent.clientHeight}px` : '0px';
      }, 10);
    },
  },
  methods: {
    // アニメーション終了時
    onTransitionEnd() {
      // 開いたときは高さとoverflowの設定を解除する
      if (this.$props.isOpen) {
        this.$data.heightStyle = '';
        this.$data.isOverflow = false;
      }
    },
  },
  template: `
    <div
      ref="elAccordion"
      class="accordion"
      :style="{
        height: $data.heightStyle,
        overflow: $data.isOverflow ? 'hidden' : '',
      }"
      @transitionend="onTransitionEnd"
    >
      <div
        ref="elContent"
      >
        <slot></slot>
      </div>
    </div>
  `,
});

終わりに

以上がアコーディオンを自作する場合の方法でした。
最後にサンプルコードを置きますので、詳しい実装はこちらを参考にしてみてください。

See the Pen アコーディオン by wintyo (@wintyo) on CodePen.

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?