如何让FullCalendar Vue3组件根据用户选择实现刷新?
问题描述
在Laravel Breeze/Vue项目中使用FullCalendar Vue3组件,希望切换下拉选择框的用户后,日历能刷新展示对应用户的日程,但一直无法实现。采用Vue3组合式API(Composition API),尝试通过Calendar API强制刷新但无效。
页面加载时事件可正常加载且无报错,但切换用户调用refresh_calendar()函数时出现报错。
简化后的代码如下:
<script setup> import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue'; import { reactive, ref, computed, watch, onMounted, onUnmounted, nextTick } from "vue"; import { Head, Link, useForm, router } from '@inertiajs/vue3'; import FullCalendar from '@fullcalendar/vue3'; import dayGridPlugin from '@fullcalendar/daygrid'; import timeGridPlugin from '@fullcalendar/timegrid'; import interactionPlugin from '@fullcalendar/interaction'; const props = defineProps({ 'calendar_users': Object, }); const calendarFor = reactive({ id: -1, }); const calendarOptions = reactive({ plugins: [ dayGridPlugin, timeGridPlugin, interactionPlugin, ], initialView: 'dayGridMonth', headerToolbar: { start: 'prevYear,nextYear prev,next today', center: 'title', end: 'dayGridMonth,timeGridWeek,timeGridDay' }, events: '/get_events' + '?user=' + calendarFor.id, height: 'auto', }); function refresh_calendar() { let calApi = this.$refs.fullCalendar.getApi(); calApi.refetchEvents(); } </script> <template> <Head title="Calendar" /> <AuthenticatedLayout> <template #header> <h2 class="font-semibold text-xl text-gray-800"> Office Calendar </h2> </template> <div class="py-3"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> <div class="bg-white overflow-hidden sm:rounded-lg" id="CalendarScreen" name="CalendarScreen"> <div class="flex"> <div v-if="true" id="left_side" class="min-w-48 m-1 border"> <div class="flex mt-8"> <label for="calendarFor" class="ml-3 mr-4 font-bold text-lg">Calendar for:</label> <select v-model="calendarFor.id" class=" border rounded-md" id="calendarFor" @change="refresh_calendar()"> <option value="-1">****</option> <option v-for="calendar_user in props.calendar_users" :key="calendar_user.id" :value="calendar_user.id"> {{ calendar_user.initials }} </option> </select> </div> </div> <div id="right_side" class=""> <div class="p-4 text-gray-900"> <FullCalendar ref='fullCalendar' :options="calendarOptions" /> </div> </div> </div> </div> </div> </div> </AuthenticatedLayout> </template>
错误原因分析
this指向错误:Vue3的<script setup>语法中,this不指向组件实例,直接使用this.$refs.fullCalendar会导致this为undefined,无法获取日历实例。events参数静态绑定:初始化时events字符串是一次性拼接的,后续calendarFor.id变化时,请求URL不会自动更新,调用refetchEvents()仍会请求旧用户ID的数据。- 未正确声明ref变量:
<script setup>中需用ref()显式声明DOM引用变量,才能通过变量访问组件实例。
修复方案
- 用
ref()声明日历组件的引用变量,替代this.$refs的方式。 - 将
events改为函数形式,每次获取事件时动态计算当前用户ID,确保请求URL为最新值。 - 修正
refresh_calendar()函数,通过声明的ref变量获取日历API并刷新事件。
修复后的完整代码
<script setup> import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue'; import { reactive, ref, watch } from "vue"; import { Head } from '@inertiajs/vue3'; import FullCalendar from '@fullcalendar/vue3'; import dayGridPlugin from '@fullcalendar/daygrid'; import timeGridPlugin from '@fullcalendar/timegrid'; import interactionPlugin from '@fullcalendar/interaction'; const props = defineProps({ calendar_users: Object, }); const calendarFor = reactive({ id: -1, }); // 声明日历组件的ref变量 const fullCalendar = ref(null); const calendarOptions = reactive({ plugins: [ dayGridPlugin, timeGridPlugin, interactionPlugin, ], initialView: 'dayGridMonth', headerToolbar: { start: 'prevYear,nextYear prev,next today', center: 'title', end: 'dayGridMonth,timeGridWeek,timeGridDay' }, // 改为函数形式,动态生成请求URL events: function(info, successCallback, failureCallback) { fetch(`/get_events?user=${calendarFor.id}`) .then(response => response.json()) .then(events => successCallback(events)) .catch(error => failureCallback(error)); }, height: 'auto', }); function refresh_calendar() { // 通过ref变量获取日历API if (fullCalendar.value) { const calApi = fullCalendar.value.getApi(); calApi.refetchEvents(); } } // 监听calendarFor.id变化,自动触发刷新 watch(() => calendarFor.id, () => { refresh_calendar(); }); </script> <template> <Head title="Calendar" /> <AuthenticatedLayout> <template #header> <h2 class="font-semibold text-xl text-gray-800"> Office Calendar </h2> </template> <div class="py-3"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> <div class="bg-white overflow-hidden sm:rounded-lg" id="CalendarScreen"> <div class="flex"> <div id="left_side" class="min-w-48 m-1 border"> <div class="flex mt-8"> <label for="calendarFor" class="ml-3 mr-4 font-bold text-lg">Calendar for:</label> <select v-model="calendarFor.id" class="border rounded-md" id="calendarFor"> <option value="-1">****</option> <option v-for="calendar_user in props.calendar_users" :key="calendar_user.id" :value="calendar_user.id"> {{ calendar_user.initials }} </option> </select> </div> </div> <div id="right_side"> <div class="p-4 text-gray-900"> <!-- 将ref绑定到声明的变量 --> <FullCalendar ref="fullCalendar" :options="calendarOptions" /> </div> </div> </div> </div> </div> </div> </AuthenticatedLayout> </template>
内容的提问来源于stack exchange,提问作者Bill200
相关产品推荐
相关产品推荐

