Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What is going on with this article?
@wintyo

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

More than 1 year has passed since last update.

始めに

アコーディオンは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.

5
Help us understand the problem. What is going on with this article?
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
wintyo
フロントエンド4年目です。TypeScriptとVue.jsをメインで使っています。 最近はReact hooksも触り始めました。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
5
Help us understand the problem. What is going on with this article?