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

# `<component>`の使用
１か所の要素から複数のモーダルを条件に応じて切り替えて表示させる方法

```
          <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"
          />
```

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

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

# ポイント２
🔍 解説：
✅ `: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 → 英単語・スピーキング評価など