You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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引用变量,才能通过变量访问组件实例。
修复方案
  1. 用ref()声明日历组件的引用变量,替代this.$refs的方式。
  2. 将events改为函数形式,每次获取事件时动态计算当前用户ID,确保请求URL为最新值。
  3. 修正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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 03:45:10