Vueの開閉可能なパネルコンポーネントを作成する

デザイン

BULMAのスタイルを使用したパネルで開閉が行えるコンポーネントを作成します。
今回は独立した一つのパネルの開閉を制御します。 アコーディオンのように複数表示して、一つを開くと他が閉じるようなコンポーネントは別の機会で作成しようと思います。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<template>
  <div class="panel folding-panel">
    <p
      class="panel-heading panel-heading-text"
      :class="{
        'is-open-panel-heading': isUnfoldedPanel,
        'is-close-panel-heading': isFoldedPanel
      }"
      @click="onPanelHeadingClick($event)"
    >
      <span
          class="icon"
          :class="{
            'is-open-panel-icon': isUnfoldedPanel,
            'is-close-panel-icon': isFoldedPanel
      }">
        <ion-icon name="chevron-forward-outline"></ion-icon>
      </span>
      {{ panelTitle }}
    </p>
    <transition name="folding">
      <div v-show="isUnfoldedPanel"
          class="panel-body"
      >
        <slot>

        </slot>
      </div>
    </transition>
  </div>
</template>

<script>
export default {
  name: "FoldingPanel",
  props: {
    panelId : {
      type: String,
      required: true,
      default: ""
    },
    panelTitle: {
      type: String,
      require: true,
      default: ""
    },
    initialFolded: {
      type: Boolean,
      default: false
    }
  },
  emits:['click'],
  data() {
    return {
      isFolded: false
    }
  },
  computed: {
    isUnfoldedPanel() {
      return !this.isFolded
    },
    isFoldedPanel() {
      return !!this.isFolded
    }
  },
  methods: {
    onPanelHeadingClick() {
      this.isFolded = !this.isFolded

      this.$emit('click', {
        panelId: this.panelId,
        isFolded: this.isFolded
      })
    }
  },
  mounted() {
    this.isFolded = this.initialFolded
  }
}
</script>

<style scoped>
.folding-panel {
}

.panel-body {
  padding: 0;
  margin: 0;
}

.panel-heading-text {
  text-align: left;
}

.is-open-panel-heading {
  border-radius: 6px 6px 0 0;
  transition: all 0.5s ease-in-out;
}
.is-close-panel-heading {
  border-radius: 6px;
  transition: all 0.5s ease-in-out;
}
.is-open-panel-icon {
  -webkit-transform: rotate(90deg);
  transform: rotate(90deg);
  transition: 1s;
}
.is-close-panel-icon {
  -webkit-transform: rotate(0deg);
  transform: rotate(0deg);
  transition: 1s;
}

.folding-enter-active {
  transition: all 0.5s ease-out;
}
.folding-leave-active {
  transition: all 0.5s ease-in;
}
.folding-enter-from, .folding-leave-to {
  transform: translateY(-60%) scaleY(0);
  line-height: 0;
  opacity: 0;
}
</style>

感想

Webアプリを作成するときは開閉はよく使いそうな気がします。 アイコンの回転やパネルの開閉のトランジションは、他でも使用しそうなのでもう少し理解を深める必要がありそう。

リンク

開閉可能なパネルコンポーネントの追加

Last Mod: May 14, 2022