0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vueでモーダルコンポーネントの操作2

Last updated at Posted at 2025-05-04

<component>の使用

1か所の要素から複数のモーダルを条件に応じて切り替えて表示させる方法

          <component
            :is="modalComponent"
            :modalId="activeModal"
            :studentId="selectedStudentStore.current.student_id"
            :studentName="selectedStudentStore.current.student_name"
            :recordDate="selectedStudentStore.current.date"
            :subject="currentSubject"
            :isOpen="true"
            @close="closeModal"
            @confirm="handleModalSave"
          />

ポイント1

Vue.js で <component>というタグは 特別な予約タグ で、動的にコンポーネントを切り替えるための専用タグなんです。

※つまり カスタムコンポーネント ではない

ポイント2

🔍 解説:
:is は Vue の構文
:is は v-bind:is省略形で、Vue コンポーネントや HTML タグを動的に切り替えるために使われます。

動的にどのコンポーネントを表示するかを切り替えたいときに便利です。

📌 例:

<component :is="modalComponent" />

このように書くと、modalComponent の値(例えば 'ModalA' や 'ModalB' など)によって表示するコンポーネントを切り替えられます。

modalComponent にはコンポーネントを入れる変数の役割

Kiroku.vue
<template>
  <div>
    <!-- 教科ごとの記録モーダルを開くボタン -->
    <div class="flex flex-col space-y-2 mt-4">
      <button @click="handleOpenModal('modal-japanese')">国語の記録</button>
      <button @click="handleOpenModal('modal-math')">数学の記録</button>
      <button @click="handleOpenModal('modal-science')">理科の記録</button>
      <button @click="handleOpenModal('modal-english')">英語の記録</button>
    </div>

    <!-- モーダルの表示部分 -->
    <div v-if="activeModal" class="modal-content fixed inset-0 z-50">
      <div class="min-h-screen flex items-center justify-center">
        <div class="fixed inset-0 bg-gray-900/30 transition-opacity"></div>
        <div class="flex-1 overflow-y-auto p-5">
          <component
            :is="modalComponent"
            :modalId="activeModal"
            :studentId="selectedStudentStore.current.student_id"
            :studentName="selectedStudentStore.current.student_name"
            :recordDate="selectedStudentStore.current.date"
            :subject="currentSubject"
            :isOpen="true"
            @close="closeModal"
            @confirm="handleModalSave"
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { ref, computed } from 'vue';
import JapaneseModal from '../Modals/JapaneseModal.vue';
import MathModal from '../Modals/MathModal.vue';
import ScienceModal from '../Modals/ScienceModal.vue';
import EnglishModal from '../Modals/EnglishModal.vue';

import { useSelectedStudentStore } from '../stores/selectedStudent';

export default {
  name: 'SubjectRecordPage',
  components: {
    JapaneseModal,
    MathModal,
    ScienceModal,
    EnglishModal,
  },

  setup() {
    const activeModal = ref(null);
    const currentSubject = ref('');

    const selectedStudentStore = useSelectedStudentStore();

    const handleOpenModal = (modalType) => {
      activeModal.value = modalType;

      // 教科名をセット(表示や保存に使える)
      currentSubject.value = {
        'modal-japanese': '国語',
        'modal-math': '数学',
        'modal-science': '理科',
        'modal-english': '英語',
      }[modalType] || '';
    };

    const closeModal = () => {
      activeModal.value = null;
    };

    const handleModalSave = (data) => {
      console.log('保存されたデータ:', data);
      closeModal();
    };

    const modalComponent = computed(() => {
      switch (activeModal.value) {
        case 'modal-japanese':
          return JapaneseModal;
        case 'modal-math':
          return MathModal;
        case 'modal-science':
          return ScienceModal;
        case 'modal-english':
          return EnglishModal;
        default:
          return null;
      }
    });

    return {
      activeModal,
      currentSubject,
      selectedStudentStore,
      handleOpenModal,
      closeModal,
      handleModalSave,
      modalComponent,
    };
  },
};
</script>

モーダルを表示に使用する関数

    const handleOpenModal = (modalType) => {
      activeModal.value = modalType;

      // 教科名をセット(表示や保存に使える)
      currentSubject.value = {
        'modal-japanese': '国語',
        'modal-math': '数学',
        'modal-science': '理科',
        'modal-english': '英語',
      }[modalType] || '';
    };

表示するモーダルの例

JapaneseModal.vue
<template>
  <div class="bg-white rounded-xl shadow-lg p-6 w-full max-w-md mx-auto">
    <h2 class="text-xl font-semibold mb-4">{{ studentName }} さんの国語記録</h2>

    <div class="mb-4">
      <label class="block text-sm font-medium mb-1">記録日</label>
      <input type="date" v-model="recordDate" class="w-full border rounded px-3 py-2" />
    </div>

    <div class="mb-4">
      <label class="block text-sm font-medium mb-1">学習内容</label>
      <input type="text" v-model="lessonContent" class="w-full border rounded px-3 py-2" />
    </div>

    <div class="mb-4">
      <label class="block text-sm font-medium mb-1">理解度</label>
      <select v-model="understanding" class="w-full border rounded px-3 py-2">
        <option value="">選択してください</option>
        <option value="よく理解している">よく理解している</option>
        <option value="普通">普通</option>
        <option value="理解が不十分">理解が不十分</option>
      </select>
    </div>

    <div class="flex justify-end space-x-2 mt-6">
      <button @click="$emit('close')" class="px-4 py-2 bg-gray-300 rounded">キャンセル</button>
      <button @click="submit" class="px-4 py-2 bg-blue-600 text-white rounded">保存</button>
    </div>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue';

// Props
const props = defineProps({
  modalId: String,
  studentId: String,
  studentName: String,
  recordDate: String,
  subject: String,
  isOpen: Boolean,
});

// Emits
const emit = defineEmits(['close', 'confirm']);

// ローカルデータ
const lessonContent = ref('');
const understanding = ref('');
const recordDate = ref(props.recordDate);

// 保存処理
const submit = () => {
  emit('confirm', {
    studentId: props.studentId,
    subject: props.subject,
    recordDate: recordDate.value,
    lessonContent: lessonContent.value,
    understanding: understanding.value,
  });
};
</script>

📦 このモーダルができること
生徒名と日付を表示・編集

学習内容(テキスト入力)

理解度(プルダウン)

キャンセルと保存ボタンを提供

保存時に親にデータを返す(@confirm

✏️ ほかの教科にも応用できます
MathModal.vue → 数式や問題数の入力欄に変更

ScienceModal.vue → 実験内容・観察記録など

EnglishModal.vue → 英単語・スピーキング評価など

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?