Programming Journal

学習したことの整理用です。

【Vue.js】モーダルウィンドウ

実装したいこと

タスク一覧があり、それぞれのタスクタイトルをクリックすると、モーダルウィンドウでタスクの詳細が表示される。

データの流れ

細かいコード内容は省き、大まかな流れだけ追います。
データの流れの説明に必要な部分だけ切り取っているので、インデントぐちゃぐちゃです…

親側

<template>
<!-- 必要部分だけ抜粋 -->
<!-- ①各タスク名をクリックすると"handleOpenTaskDetailModal(task)"発火 -->
        <div
          v-for="task in tasks"
          :key="task.id"
          @click="handleOpenTaskDetailModal(task)"   
          >
            <span>{{ task.title }}</span>
        </div>
<!-- ③親から子に属性としてデータを渡す -->
<!-- isVisibleTaskDetailModalをtrue/falseに切り替えることで、子コンポーネントの表示・非表示をv-ifで実現する。-->
    <transition name="fade"> <!-- ⑨v-on(@に省略可)で子から$emitで渡された'close-modal'を受け取り、メソッド発火 -->
      <TaskDetailModal :task="taskDetail" v-if="isVisibleTaskDetailModal" @close-modal="handleCloseTaskDetailModal" /> 
    </transition>

</template>

<script>
import TaskDetailModal from '../../components/TaskDetailModal.vue' //2階層上なので、../../となる

export default {
  name: "TaskIndex",
  components: {
    TaskDetailModal
  },
  data() { //初期値を設定する(設定しないと警告がでる)
    return {
      tasks: [],
      taskDetail: {},
      isVisibleTaskDetailModal: false
    }
  },

  methods: {
// ②各タスククリックで発火される
    handleOpenTaskDetailModal(task) { 
      this.isVisibleTaskDetailModal = true; // trueにすることで表示
      this.taskDetail = task; // ループして引数で受けとったtaskを`taskDetail`に入れる※子側で使う
    },
// ⑩子から$emitで渡された'close-modal'により発火するメソッド
    handleCloseTaskDetailModal() {
      this.isVisibleTaskDetailModal = false; //非表示にするためにfalseにする
      this.taskDedail= {};
    }
  }
}
</script>

子側

templateはBootstrapからコピペして少々修正しただけです。
親から属性で渡されたデータをpropsで受け取ります。
このとき、受け取るデータ型を指定します。(指定しないと警告がでる)

<template>
<!-- 必要部分だけ抜粋 -->
<!-- ⑤親から受け取ったデータtask, descriptionを表示 -->
          <h5 class="modal-title">{{ task.title }}</h5> 

          <div class="modal-body" v-if="task.description">
            <p>{{ task.description }}</p>
          </div>

          <div class="modal-footer"> <!-- ⑥閉じるボタンをクリックすると、"handleCloseModal"メソッドが発火する -->
            <button @click="handleCloseModal" class="btn btn-secondary" data-dismiss="modal">閉じる</button>
          </div>

</template>

<script>
export default {
  name: 'TaskDetailModal',
  props: {  // ④親からデータ受け取り
    task: {
      title: {
        type: String, //データ型指定
        required: true
      },
      description: {
        type: String,
        required: true
      }
    }
  },
  methods: {
    handleCloseModal() {  // ⑦閉じるボタンクリックにより発火する。
      this.$emit('close-modal') // ⑧$emitで'close-modal'を親側に渡す。
    }
  }
}
</script>

<style scoped>
  .modal{
    display: block;
  }
</style>

データが行ったりきたりして混乱するので、自分で図を書いてみるとわかりやすかったです。

参考

【Vue.js】動的なモーダルウインドウの作り方を解説

モーダルウィンドウ | 基礎から学ぶ Vue.js

Modal - Bootstrap 4.2 - 日本語リファレンス