暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

如何使用FullCalendar实现事件日历管理

原创 浮游 2024-11-14
1871

FullCalendar 是一个功能强大的 JavaScript 日历插件,它可以用来创建和管理事件日历。它支持多种视图(月视图、周视图、日视图等),并且可以轻松地与其他库(如 Vue.js)集成。下面我们将详细介绍如何使用 FullCalendar 实现事件日历管理。

实现效果大致如下:

image.png

安装和引入 FullCalendar

首先,你需要安装 FullCalendar 及其相关插件。可以通过 npm 来安装:

npm install @fullcalendar/core @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/list @fullcalendar/interaction

安装完成后,你需要在你的项目中引入 FullCalendar 及其插件:

import { Calendar } from '@fullcalendar/core'; import dayGridPlugin from '@fullcalendar/daygrid'; import timeGridPlugin from '@fullcalendar/timegrid'; import listPlugin from '@fullcalendar/list'; import interactionPlugin from '@fullcalendar/interaction';

初始化 FullCalendar

在 Vue 组件中,你可以在 mounted 钩子中初始化 FullCalendar。首先,你需要在模板中定义一个容器元素,然后在 mounted 钩子中创建一个新的 Calendar 实例,并将其挂载到 DOM 上。

const fullcalendar = ref(null); onMounted(() => { const calendar = new Calendar(fullcalendar.value, { plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin], // 其他配置... }); calendar.render(); });

配置 FullCalendar

FullCalendar 提供了许多配置选项,你可以根据需要进行自定义。例如,你可以设置日历的视图类型、语言、事件数据等。以下是一些常见的配置选项:

const calendar = new Calendar(fullcalendar.value, { plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin], initialView: 'dayGridMonth', // 初始视图 locale: 'zh-cn', // 语言设置 editable: true, // 允许编辑事件 selectable: true, // 允许选择日期 events: [ // 事件数据 { title: '事件1', start: '2023-04-01' }, { title: '事件2', start: '2023-04-02', end: '2023-04-03' }, ], // 更多配置... });

事件处理

FullCalendar 允许你为不同的用户交互定义处理函数,例如点击事件、选择日期等。你可以通过配置选项来添加这些处理函数:

const calendar = new Calendar(fullcalendar.value, { // ... eventClick: function(info) { // 处理事件点击 alert('点击了事件: ' + info.event.title); }, select: function(info) { // 处理日期选择 alert('选择了日期范围: ' + info.startStr + ' 到 ' + info.endStr); }, // 更多事件处理... });

更新事件数据

当你的事件数据发生变化时,你可能需要更新日历上的事件。FullCalendar 提供了方法来添加、删除和更新事件:

// 添加事件 calendar.addEvent({ title: '新事件', start: '2023-04-10' }); // 删除事件 let event = calendar.getEventById('event-id'); if (event) { event.remove(); } // 更新事件 event.setProp('title', '更新后的事件标题');

集成到 Vue 组件中

在 Vue 组件中使用 FullCalendar 时,你可以将日历实例和事件数据存储在组件的状态中,并在状态变化时更新日历:

const state = reactive({ events: [ // 初始事件数据 ], }); // 在事件数据变化时更新日历 watch(() => state.events, (newEvents) => { calendar.removeAllEvents(); calendar.addEventSource(newEvents); });

结合后端 API

在实际应用中,你可能需要从后端 API 获取事件数据,并在用户进行操作(如添加、编辑、删除事件)时与后端进行交互。你可以使用 Vue 的生命周期钩子和异步函数来实现这一功能:

onMounted(async () => { // 从后端获取事件数据 const events = await fetchEventsFromAPI(); state.events = events; // 初始化日历 initCalendar(); }); const addEvent = async (event) => { // 将新事件发送到后端 await saveEventToAPI(event); // 更新状态 state.events.push(event); };

结语

FullCalendar 是一个功能丰富且灵活的日历插件,它可以帮助你轻松实现事件日历管理。通过上述介绍,你应该已经了解了如何在 Vue 组件中使用 FullCalendar,以及如何配置、处理事件和与后端 API 集成。希望这篇文章能够帮助你在项目中实现高效的日历管理功能。

具体代码实现

<template> <div ref="fullcalendar" class="card"></div> </template> <script setup lang="ts"> import { ref, reactive, toRefs, nextTick, onMounted, watch, computed } from 'vue' import { Calendar } from '@fullcalendar/core' import dayGridPlugin from '@fullcalendar/daygrid' import timeGridPlugin from '@fullcalendar/timegrid' import listPlugin from '@fullcalendar/list' import interactionPlugin from '@fullcalendar/interaction' import dayjs from 'dayjs' import { useRoute, useRouter } from 'vue-router' import ESDialogVue from '@/components/ESDialog.vue' import { useServiceOrg } from '../pages/compositions/ServiceOrg' const { coms, getCompany, cloneComs } = useServiceOrg() import { xxxApi } from '@/apis' import useMapStore from '@/compositions/mapStore' const { user, isSys, isDba, isPA } = useMapStore() import useAdmq from '@/compositions/admq' import { cbSuccess, rules } from '@/utils' const route = useRoute() const router = useRouter() const state = reactive({ showManHour: false, manHourInfo: { title: '', type: 0, rid: '', start: '', end: '', taskTime: '', companyId: '', executorId: isSys.value ? '' : user.value.userId, remark: '' } as any, serviceList: [], planList: [], executor: {} as any, infoList: [] as any, taskTimeTotalList: [] as any, activeStartDate: null, activeEndDate: null, Tcalendar: ref(), selectedEvent: null, executorId: undefined, users: [] }) const fullcalendar = ref() const Tcalendar = ref() const type = ref('dayGridMonth') const currentData = ref() const { showManHour, manHourInfo, serviceList, planList, executor } = toRefs(state) const setType = (path: any) => { router.push(path) } const fetchData = async () => { let _params = { userId: +route.params.id, startDate: dayjs(state.activeStartDate).format('YYYY-MM-DD'), endDate: dayjs(state.activeEndDate).format('YYYY-MM-DD') } let { data } = await getManHourListApi(_params) state.infoList = data.taskList state.taskTimeTotalList = data.taskTimeTotalList } const getLabel = async (item: any) => { state.executor = [ { employeeName: item.executorName, userId: item.executorId } ] coms.value = [ { id: item.companyId, name: item.companyName } ] } const updateCalendar = () => { if (Tcalendar.value) { Tcalendar.value.removeAllEvents() Tcalendar.value.addEventSource(state.infoList) Tcalendar.value.render() } } const initCalendar = () => { Tcalendar.value = new Calendar(fullcalendar.value, { plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin], initialView: type.value, aspectRatio: 2.2, locale: 'zh-cn', handleWindowResize: true, // height: 'auto', // loading: loading //控制表格加载 editable: false, // 允许编辑表格 droppable: false, //允许从外部拖拽进入日历 eventDurationEditable: false, //控制时间段是否可以拖动 eventResizableFromStart: false, //控制事件是否可以拖动 selectable: false, // 允许用户通过单击和拖动来突出显示多个日期或时间段 firstDay: 1, // 设置一周中显示的第一天是哪天,周日是0,周一是1,类推。 unselectAuto: true, // 当点击页面日历以外的位置时,是否自动取消当前的选中状态 dayMaxEvents: 4, //在dayGrid视图中,给定日期内的最大事件数 headerToolbar: false, // 关闭默认日历头部,采取自定义的方式切换日历视图 allDaySlot: false, nowIndicator: true, eventMaxStack: 2, events: state.infoList, //主要数据 slotMinTime: '09:00:00', //时间最大范围 slotMaxTime: '21:00:00', //时间最小范围 slotDuration: '00:15:00', //时间间段 slotLabelFormat: { hour: '2-digit', minute: '2-digit', omitZeroMinute: false, meridiem: 'short' }, datesSet: function (info) { state.activeStartDate = info.start state.activeEndDate = info.end }, eventClick: function (info) { state.manHourInfo = { id: info.event.id, title: info.event.title, type: info.event.extendedProps.type, rid: info.event.extendedProps.rid, start: dayjs(info.event.start).format('YYYY-MM-DD HH:mm:ss'), end: dayjs(info.event.end).format('YYYY-MM-DD HH:mm:ss'), taskTime: info.event.extendedProps.taskTime, companyId: info.event.extendedProps.companyId, executorId: info.event.extendedProps.executorId, remark: info.event.extendedProps.remark } fetchService(info.event.extendedProps.rid, true) getLabel(info.event.extendedProps) state.manHourInfo.daterange = [state.manHourInfo.start, state.manHourInfo.end] state.showManHour = true }, eventClassNames: function (arg) { // 添加自定义class return [arg.event.extendedProps.class] }, dayCellContent: function (arg) { if (!state.taskTimeTotalList) return { html: arg.dayNumberText } const hoursForDay = state.taskTimeTotalList.find((item: any) => item.date === dayjs(arg.date).format('YYYY-MM-DD')) const hours = hoursForDay ? hoursForDay.hours : 0 let hoursHtml = '' if (hours > 0) { hoursHtml = `<div class="fc-daygrid-day-hours mt5 f13">工时:${hours} 小时</div>` } return { html: ` <div class="fc-daygrid-day-top"> <a class="fc-daygrid-day-number">${arg.dayNumberText}</a> </div> ${hoursHtml} ` } }, eventContent: function (arg) { const italicEl = document.createElement('div') italicEl.className = 'fc-event-container' const titleEl = document.createElement('div') titleEl.setAttribute('class', 'plan_title') const titleTextEl = document.createElement('div') titleTextEl.className = 'plan_title_text' titleTextEl.textContent = arg.event.title titleEl.appendChild(titleTextEl) const tooltip = document.createElement('div') tooltip.className = 'fc-event-tooltip' tooltip.textContent = arg.event.title italicEl.appendChild(titleEl) italicEl.appendChild(tooltip) // 时间 const timeEl = document.createElement('span') timeEl.innerHTML = dayjs(arg.event.start).format('HH:mm') + '-' + dayjs(arg.event.end).format('HH:mm') titleEl.append(timeEl) italicEl.append(titleEl) italicEl.setAttribute('class', `plan_card`) italicEl.addEventListener('mouseenter', () => { const rect = italicEl.getBoundingClientRect() tooltip.style.left = `${rect.left}px` tooltip.style.top = `${rect.top - 40}px` tooltip.style.display = 'block' }) italicEl.addEventListener('mouseleave', () => { tooltip.style.display = 'none' }) return { domNodes: [italicEl] } }, noEventsContent: function () { const noEl = document.createElement('div') noEl.innerHTML = '暂无日程安排,请安排相关日程' return { domNodes: [noEl] } } }) Tcalendar.value.render() } const dayTime = () => { if (type.value === 'dayGridMonth') { currentData.value = dayjs(Tcalendar.value.getDate()).format('YYYY年MM月') } else if (type.value === 'timeGridWeek' || type.value === 'listWeek') { currentData.value = dayjs(Tcalendar.value.getDate()).format('YYYY年MM月DD日') + ' - ' + dayjs(Tcalendar.value.getDate()).add(6, 'day').format('DD日') } else if (type.value === 'timeGridDay') { currentData.value = dayjs(Tcalendar.value.getDate()).format('YYYY年MM月DD日') } fetchData() } const toToday = () => { Tcalendar.value.today() dayTime() } const toPrev = () => { Tcalendar.value.prev() dayTime() } const toNext = () => { Tcalendar.value.next() dayTime() } onMounted(() => { nextTick(() => { initCalendar() }) }) </script>
最后修改时间:2024-11-14 16:46:10
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论