背景
有一些应用系统或应用功能,如日程管理、任务管理需要使用到日历组件。虽然Element Plus也提供了日历组件,但功能比较简单,用来做数据展现勉强可用。但如果需要进行复杂的数据展示,以及互动操作如通过点击添加事件,则需要做大量的二次开发。
FullCalendar是一款备受欢迎的开源日历组件,以其强大的功能而著称。其基础功能不仅免费且开源,为开发者提供了极大的便利,仅有少量高级功能需要收费。然而,尽管该组件功能卓越,其文档却相对简洁,导致在集成过程中需要开发者自行摸索与探索,这无疑增加了不少学习和验证的时间成本。
为此,本专栏通过日程管理系统的真实案例,手把手带你了解该组件的属性和功能,通过需求导向的方式,详细阐述FullCalendar组件的集成思路和实用解决方案。
在介绍过程中,我们将重点关注集成要点和注意事项,力求帮助开发者在集成过程中少走弯路,提供有效的避坑指南,从而提升开发效率,更好地利用这款优秀的日历组件。
官网:https://fullcalendar.io/
环境Vue3+Element Plus+FullCalendar 6.1.11。
使用
全天与非全天区域拖动引发的结束时间清空问题(二)
实现方案
最终实现逻辑代码如下:
// 拖动结束
eventDrop(arg) {
const allDay = arg.event.allDay
const plannedDuration = arg.event.extendedProps.plannedDuration
const start = arg.event.start
let end = arg.event.end
console.log('before', end)
if (allDay) {
// 拖动结束位于全天事件区域
if (end == null) {
// 拖动结束时间为空,则设置为开始时间+1天
end = new Date(start.getTime() + 24 * 60 * 60 * 1000)
}
} else {
// 拖动结束位于非全天事件区域
if (end == null && plannedDuration != null) {
// 拖动结束时间为空且计划时长不为空,则设置为开始时间+计划时长
end = new Date(start.getTime() + plannedDuration * 60 * 60 * 1000)
}
}
console.log('after', end)
arg.event.setEnd(end)
this.changeTime(arg)
}
以上增加了判断结束时间是否为空的逻辑,是过滤掉区域内移动的情况。
上面处理过程中需要用到任务的计划时长属性,这不是一个FullCalendar组件的事件对象自身属性,在加载数据环节,需要将该属性放到事件对象的扩展属性extendedProps中。
// 加载数据
loadData() {
this.$api.personaltask.task.listWithScope(this.startTime, this.endTime).then((res) => {
if (res.data) {
const eventArray = res.data.map((item) => {
// 若起止时间均为00:00:00,则设置为allDay属性为true
let allDay = false
if (
item.startTime &&
item.endTime &&
item.startTime.substr(11, 8) === '00:00:00' &&
item.endTime.substr(11, 8) === '00:00:00'
) {
allDay = true
}
return {
id: item.id,
title: item.name,
start: item.startTime,
end: item.endTime,
allDay: allDay,
status: item.status,
extendedProps: {
priority: item.priority,
plannedDuration: item.plannedDuration
}
}
})
this.eventData = eventArray
this.filteData()
}
})
}
测试各种场景下的移动,区域内移动、区域间移动、结束时间有值、结束时间无值,均能正常处理。
并且当任务设置了计划时长的时候,从全天区域拖放到具体的开始时间,系统会自动将结束时间设置为开始时长和计划时长的和,更符合用户的期望。
可选方案
在摸索解决的过程中,发现了FullCalendar自带的一个属性allDayMaintainDuration。
其作用是确定一个事件的持续时间全天与非全天两个区域间拖动应该如何变化,该值默认为false,未开启状态。看说明这个参数跟我们期望实现的需求密切相关,于是动手验证了下。
当设置为false时(这是默认值),事件的持续时间将根据它被拖放到的部分进行重置。如果事件被拖放到全天区域,它的持续时间将重置为defaultAllDayEventDuration(可能是一天)。如果事件被拖放到非全天区域,它的持续时间将重置为defaultTimedEventDuration(可能是一个小时)。
官方说明是这样,但所谓的重置,实际只是前端显示看上去时一整体或一小时,当会将事件对象中的结束时间属性清空掉,在进行调用后端服务持久化时导致结束时间丢失。
当设置为true时,事件在被拖放到全天区域或从全天区域拖出后,其持续时间将大致保持不变。这里所说的“大致”是因为如果一个事件的持续时间具有小时级的精度,它将被向下舍入到最近的整天。这意味着,如果一个事件原本跨越了数个小时但不是一整天,当它被拖放到全天区域时,它的持续时间将被调整为整个日历日。
测试了下效果,非全天事件拖放到全天区域,结束时间会自动变更为当天结束,不会置空;全天事件拖放到非全天区域,起止时间自动变成0点到24天,结束时间不会置空,但是一下占满当天所有时段,用户体验是比较差的,需要通过缩放操作调整起止时间。
该方式最大的优点就是简便,不需要进行复杂的二次开发,开启一个参数配置即可;最大的缺点就是用户体验较差,明显不如我们前面进行的二次扩展,结合了任务计划时长进行了自动化处理工作。