Nuxt.jsで動的コンポーネントを使って簡単に切り替え可能なモーダルを実装する

こんにちは、あかしぃです。

Nuxt.jsで、動的コンポーネントを使ったモーダルの実装方法を解説します。Nuxt.jsで、と書いていますが、記述方法はVue.jsでも基本的に同じはずです。

動的コンポーネント

動的コンポーネントとは、「is」属性を使って、コンポーネント内の子コンポーネントを動的に切り替えられるコンポーネントのことです。

言葉ではいまいち伝わりにくいかもしれませんが、Vue公式に例があるので、そちらを参考にしてください。

Vue.js公式

動的コンポーネントを使えば、「あるページにおいてクリックされる要素(ボタン)ごとに、モーダル内の表示を変える」といったことが簡単にできます。

実装方法

まず、モーダルを表示させる元のページを作ります。

sample.vue

<template>
  <button @click="showModal1">モーダル1を表示</button>
  <button @click="showModal2">モーダル2を表示</button>

  <modal-wrapper
    v-if="showModal"
    @close="closeModal">
    <component :is="currentModalComponent" />
  </modal-wrapper>
</template>

<script>
import ModalWrapper from '@/components/ModalWrapper.vue'
import Modal1 from '@/components/Modal1.vue'
import Modal2 from '@/components/Modal2.vue'

export default {
  components: {
    ModalWrapper,
    Modal1,
    Modal2
  },

  data() {
    return {
      showModal: false,
      currentModalComponent: Modal1
    }
  },

  methods: {
    showModal1() {
      this.currentModalComponent = Modal1
      this.showModal = true
    },

    showModal2() {
      this.currentModalComponent = Modal2
      this.showModal = true
    },

    closeModal() {
      this.showModal = false
    }
  }
}
</script>

 

※ cssは省略

モーダルは同一デザインのものを使いまわしたいので、ModalWrapperでラップしています。

また、componentのis属性にcurrentModalComponentをバインディングさせています。

これにより、currentModalComponentが変化することで、表示されるモーダルの中身が変化します。

 

currentModalComponentを更新するのはModal1とModal2メソッドですね。クリックされるボタンによって発火するメソッドが異なるので、自由にcurrentModalComponentを変更することができます。

モーダルの表示/非表示を担うshowModalについてですが、これの管理はvuexに任せてもいいかもしれません。今回は子コンポーネントからのイベント伝達(emit)で更新させることにしています。

 

次に、ModalWrapperです。

components/ModalWrapper.vue

<template>
 <div
   class="modal-mask"
   @click="closeModal">
   <div class="modal-container">
     <slot />
   </div>
 </div>
</template>

<script>
export default {
  methods: {
    closeModal() {
      this.$emit('close')
    }
  }
}
</script>

<style lang='scss' scoped>
.modal-mask {
  position: fixed;
  z-index: 9998;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);

  .modal-container {
    width: 90%;
    height: 85%;
    margin: 15% auto;
    padding: 20px 30px;
    background-color: white;
    text-align: center;
    overflow-y: auto;
  }
}
</style>

 

中に子コンポーネントを入れる予定のコンポーネントなので、<slot>タグを用いています。

ModalWrapperの役割は、背景を暗くするといったデザイン面と、子コンポーネントからcloseイベントを伝達することです。

また、背景がクリックされてもモーダルをクローズさせたいので、背景部分にclickイベントを実装しています。

 

最後に、モーダルの中身となるModal1、Modal2です。

components/Modal1.vue, Modal2.vue

<template>
  <div class="modal">
    <p>Hello! I'm Modal1(or 2)!</p>
    <button @click="closeModal">
  </div>
</tempalte>

<script>
export default {
  methods: {
    closeModal() {
      this.$emit('close')
    }
  }
}
</script>

 

ボタンのclickイベントで、closeModalメソッドが発火します。そしてcloseイベントが親コンポーネントに伝達され、showModalがfalseになり、モーダルが非表示になるという仕組みです。

まとめ

今回の用途はモーダルの切り替えでしたが、他にもいろいろ使い道がありそうです。

他にも使えていないVue.jsの機能があるので、それらも積極的に使っていきたいです。

April 06, 2019 - posted by akashixi