Help us understand the problem. What is going on with this article?

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

始めに

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

https://www.npmjs.com/package/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.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away