使用 fullcalendar.js 如何在日历的每个空单元格上显示时段开始?
Using fullcalendar.js how do I display slot time start on every empty cell of the calendar?
使用全日历库,我想在我的日历上显示每个空单元格的开始时间(空单元格是下面屏幕截图中标有红叉或红点的单元格,我修改了一些方面日历):
所以我的预期输出是一个日历,时间段变成按钮,当您单击时,您开始预订 30 分钟约会的过程,该约会将在书面时间开始(绿色槽是以下屏幕截图中的悬停效果):
阅读完整日历文档后,我找不到任何简单的方法来完成它:https://fullcalendar.io/docs
附属问题,我在CSS中找不到改变空单元格样式的方法。无法通过我的 Chrome 控制台管理 select 元素。
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
columnHeaderHtml: function(date) {
if (date.getUTCDay() === 0) {
var date_day = "Lundi";
}
if (date.getUTCDay() === 1) {
var date_day = "Mardi";
}
if (date.getUTCDay() === 2) {
var date_day = "Mercredi";
}
if (date.getUTCDay() === 3) {
var date_day = "Jeudi";
}
if (date.getUTCDay() === 4) {
var date_day = "Vendredi";
}
if (date.getUTCDay() === 5) {
var date_day = "Samedi";
}
if (date.getUTCDay() === 6) {
var date_day = "Dimanche";
}
if(date.getMonth() === 0)
{
var date_month = "Jan";
}
if(date.getMonth() === 1)
{
var date_month = "Fev";
}
if(date.getMonth() === 2)
{
var date_month = "Mar";
}
if(date.getMonth() === 3)
{
var date_month = "Avr";
}
if(date.getMonth() === 4)
{
var date_month = "Mai";
}
if(date.getMonth() === 5)
{
var date_month = "Juin";
}
if(date.getMonth() === 6)
{
var date_month = "Juil";
}
if(date.getMonth() === 7)
{
var date_month = "Août";
}
if(date.getMonth() === 8)
{
var date_month = "Sept";
}
if(date.getMonth() === 9)
{
var date_month = "Oct";
}
if(date.getMonth() === 10)
{
var date_month = "Nov";
}
if(date.getMonth() === 11)
{
var date_month = "Dec";
}
var day_num = date.getDate();
return '<b>'+date_day+'</b><br><small>'+day_num+" "+date_month+"</small>";
},
plugins: [ 'interaction', 'dayGrid', 'list', 'googleCalendar','timeGrid' ],
selectable: true,
defaultView: 'timeGridFourDay',
views: {
timeGridFourDay: {
type: 'timeGrid',
duration: { days: 4 },
buttonText: '4 day'
}
},
slotLabelFormat:{
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: true,
meridiem: 'short'
},
locale:'fr',
header: {
left: 'prev today',
right: 'next'
},
validRange: {
start: '2019-08-05',
end: '2019-09-05'
},
allDaySlot:false,
firstDay:1,
minTime:"08:00:00",
maxTime:"20:00:00",
displayEventTime: true, // don't show the time column in list view
// THIS KEY WON'T WORK IN PRODUCTION!!!
// To make your own Google API key, follow the directions here:
// http://fullcalendar.io/docs/google_calendar/
googleCalendarApiKey: 'AIzaSyAL9K2UqkCVfV0n81mDW0iEpOJSwcklfsY',
// US Holidays
events: 'fr.fr#holiday@group.v.calendar.google.com',
eventClick: function(arg) {
arg.jsEvent.preventDefault() // don't navigate in main tab
console.log(arg);
},
select: function(info) {
console.log(info)
},
loading: function(bool) {
},
eventSources: [
{
googleCalendarId: 'contact@vetorino.com',
className: "gcalEvent"
}],
displayEventEnd:false,
events:[
{ // this object will be "parsed" into an Event Object
start: '2019-08-05 12:30:00', // a property!
end: '2019-08-05 14:00:00', // a property! ** see important note below about 'e6d' **
overlap: true,
backgroundColor:"#F7F7F7",
textColor:"#979797",
classNames:"closed",
}],
contentHeight: "auto",
});
calendar.render();
});
到目前为止,如我之前的屏幕截图所示,我只是设法让单元格为空,唯一可以找到一些信息的单元格是包含事件的单元格。
如上面评论所述,fullCalendar HTML 中没有单个元素表示 timeGrid 视图中的特定 "cell" 或 "slot"。您在屏幕上看到的网格实际上是通过将多个表格层叠在一起而产生的错觉。
因此,为了满足您对用户能够 select 在免费时段进行 20 分钟约会的要求,我可以看到两个主要选项。第一个是我通常会推荐的,使用标准的 fullCalendar 功能。第二个更像是你所要求的,但我认为它过于复杂了。
1) 此选项只是将日历设置为 20 分钟的时隙持续时间,然后有代码阻止用户 select 使用更长的时间(他们不能 select由于 slotDuration
设置,周期更短。这意味着他们可以点击任何空的 space 一次,它将知道在该位置创建一个正确长度的事件。不允许用户select 任何已存在事件的插槽。(P.S。我预计在现实中您需要在添加事件之前收集更多数据,但为了演示它会立即添加一个事件。)
document.addEventListener("DOMContentLoaded", function() {
var Calendar = FullCalendar.Calendar;
var calendarEl = document.getElementById("calendar");
var calendar = new Calendar(calendarEl, {
plugins: ["timeGrid", "interaction"],
header: {
left: "prev,next today",
center: "title",
right: "timeGridFourDay"
},
defaultView: "timeGridFourDay",
views: {
timeGridFourDay: {
type: "timeGrid",
duration: { days: 4 },
buttonText: "4 day"
}
},
slotLabelFormat: {
hour: "numeric",
minute: "2-digit",
omitZeroMinute: true,
meridiem: "short"
},
allDaySlot: false,
firstDay: 1,
minTime: "08:00:00",
maxTime: "20:00:00",
contentHeight: "auto",
slotDuration: "00:20:00",
selectable: true,
select: function(info) {
//console.log(info);
calendar.addEvent({ "title": "Test", start: info.start, end: info.end })
calendar.unselect();
},
selectOverlap: false,
selectAllow: function(selectInfo) {
var stM = moment(selectInfo.start);
var enM = moment(selectInfo.end);
var diff = enM.diff(stM, "minutes");
console.log(diff);
if (diff > 20)
{
return false;
}
return true;
},
events: [
{ "title": "Existing event", "start": "2019-08-08 10:00", "end": "2019-08-08 10:20"},
{ "title": "Existing event", "start": "2019-08-08 13:20", "end": "2019-08-08 13:40"},
]
});
calendar.render();
});
演示:https://codepen.io/ADyson82/pen/aeqJQg
2) 此选项更接近您想要的 UI(来自您的第二个屏幕截图),但实现起来有点复杂。我个人也认为它会让您的日历看起来很混乱,并且更难看到空闲和忙碌的位置,但最终取决于您想要如何实现它。这通过添加第二个事件源来实现,其中包含所有当前空闲插槽的列表。然后这些用于在其中心显示每个空闲插槽的开始时间。它们的颜色与现有事件不同(表示忙时隙),因此更容易区分。
当然,这需要您使用服务器端代码计算数据库中所有当前空闲的插槽,并使用该信息填充第二个事件源。 (在演示中,空闲插槽数据是静态的,但当然这在实际应用程序中是行不通的。)
document.addEventListener("DOMContentLoaded", function() {
var Calendar = FullCalendar.Calendar;
var calendarEl = document.getElementById("calendar");
var calendar = new Calendar(calendarEl, {
plugins: ["timeGrid", "interaction"],
header: {
left: "prev,next today",
center: "title",
right: "timeGridFourDay"
},
defaultView: "timeGridFourDay",
views: {
timeGridFourDay: {
type: "timeGrid",
duration: { days: 4 },
buttonText: "4 day"
}
},
slotLabelFormat: {
hour: "numeric",
minute: "2-digit",
omitZeroMinute: true,
meridiem: "short"
},
allDaySlot: false,
firstDay: 1,
minTime: "08:00:00",
maxTime: "20:00:00",
contentHeight: "auto",
slotDuration: "00:20:00",
displayEventTime: false,
eventClick: function(info) {
if (info.event.extendedProps.type == "free") {
calendar.addEvent({
title: "Test",
start: info.event.start,
end: info.event.end
});
info.event.remove(); //delete the "free slot" event
}
},
eventSources: [
{
id: "busy",
events: [
{
title: "Existing event",
start: "2019-08-08 10:00",
end: "2019-08-08 10:20"
},
{
title: "Existing event",
start: "2019-08-08 13:20",
end: "2019-08-08 13:40"
}
]
},
{
id: "free",
backgroundColor: "green",
events: [
{
title: "08:00",
start: "2019-08-08 08:00",
end: "2019-08-08 08:20",
type: "free"
},
{
title: "08:20",
start: "2019-08-08 08:20",
end: "2019-08-08 08:40",
type: "free"
},
{
title: "08:40",
start: "2019-08-08 08:40",
end: "2019-08-08 09:00",
type: "free"
},
{
title: "09:00",
start: "2019-08-08 09:00",
end: "2019-08-08 09:20",
type: "free"
},
{
title: "09:20",
start: "2019-08-08 09:20",
end: "2019-08-08 09:40",
type: "free"
},
{
title: "09:40",
start: "2019-08-08 09:40",
end: "2019-08-08 10:00",
type: "free"
},
{
title: "10:20",
start: "2019-08-08 10:20",
end: "2019-08-08 10:40",
type: "free"
},
{
title: "10:40",
start: "2019-08-08 10:40",
end: "2019-08-08 11:00",
type: "free"
},
]
}
]
});
calendar.render();
});
对于这个演示,我只创建了几个 "free" 插槽(因为创建它们很乏味),但希望你能了解它开始时的样子。日历。当然,您可以再次根据您的要求修改 CSS。
演示:https://codepen.io/ADyson82/pen/JgpNEX
(您当然可以进一步修改 CSS 使其看起来更像您想要的外观。)
附录:这是 OP 的最终版本,适用于对最终产品感兴趣的任何人 - 基于对上述建议的考虑:https://codepen.io/hugo-trial/pen/rXdajv
使用全日历库,我想在我的日历上显示每个空单元格的开始时间(空单元格是下面屏幕截图中标有红叉或红点的单元格,我修改了一些方面日历):
附属问题,我在CSS中找不到改变空单元格样式的方法。无法通过我的 Chrome 控制台管理 select 元素。
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
columnHeaderHtml: function(date) {
if (date.getUTCDay() === 0) {
var date_day = "Lundi";
}
if (date.getUTCDay() === 1) {
var date_day = "Mardi";
}
if (date.getUTCDay() === 2) {
var date_day = "Mercredi";
}
if (date.getUTCDay() === 3) {
var date_day = "Jeudi";
}
if (date.getUTCDay() === 4) {
var date_day = "Vendredi";
}
if (date.getUTCDay() === 5) {
var date_day = "Samedi";
}
if (date.getUTCDay() === 6) {
var date_day = "Dimanche";
}
if(date.getMonth() === 0)
{
var date_month = "Jan";
}
if(date.getMonth() === 1)
{
var date_month = "Fev";
}
if(date.getMonth() === 2)
{
var date_month = "Mar";
}
if(date.getMonth() === 3)
{
var date_month = "Avr";
}
if(date.getMonth() === 4)
{
var date_month = "Mai";
}
if(date.getMonth() === 5)
{
var date_month = "Juin";
}
if(date.getMonth() === 6)
{
var date_month = "Juil";
}
if(date.getMonth() === 7)
{
var date_month = "Août";
}
if(date.getMonth() === 8)
{
var date_month = "Sept";
}
if(date.getMonth() === 9)
{
var date_month = "Oct";
}
if(date.getMonth() === 10)
{
var date_month = "Nov";
}
if(date.getMonth() === 11)
{
var date_month = "Dec";
}
var day_num = date.getDate();
return '<b>'+date_day+'</b><br><small>'+day_num+" "+date_month+"</small>";
},
plugins: [ 'interaction', 'dayGrid', 'list', 'googleCalendar','timeGrid' ],
selectable: true,
defaultView: 'timeGridFourDay',
views: {
timeGridFourDay: {
type: 'timeGrid',
duration: { days: 4 },
buttonText: '4 day'
}
},
slotLabelFormat:{
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: true,
meridiem: 'short'
},
locale:'fr',
header: {
left: 'prev today',
right: 'next'
},
validRange: {
start: '2019-08-05',
end: '2019-09-05'
},
allDaySlot:false,
firstDay:1,
minTime:"08:00:00",
maxTime:"20:00:00",
displayEventTime: true, // don't show the time column in list view
// THIS KEY WON'T WORK IN PRODUCTION!!!
// To make your own Google API key, follow the directions here:
// http://fullcalendar.io/docs/google_calendar/
googleCalendarApiKey: 'AIzaSyAL9K2UqkCVfV0n81mDW0iEpOJSwcklfsY',
// US Holidays
events: 'fr.fr#holiday@group.v.calendar.google.com',
eventClick: function(arg) {
arg.jsEvent.preventDefault() // don't navigate in main tab
console.log(arg);
},
select: function(info) {
console.log(info)
},
loading: function(bool) {
},
eventSources: [
{
googleCalendarId: 'contact@vetorino.com',
className: "gcalEvent"
}],
displayEventEnd:false,
events:[
{ // this object will be "parsed" into an Event Object
start: '2019-08-05 12:30:00', // a property!
end: '2019-08-05 14:00:00', // a property! ** see important note below about 'e6d' **
overlap: true,
backgroundColor:"#F7F7F7",
textColor:"#979797",
classNames:"closed",
}],
contentHeight: "auto",
});
calendar.render();
});
到目前为止,如我之前的屏幕截图所示,我只是设法让单元格为空,唯一可以找到一些信息的单元格是包含事件的单元格。
如上面评论所述,fullCalendar HTML 中没有单个元素表示 timeGrid 视图中的特定 "cell" 或 "slot"。您在屏幕上看到的网格实际上是通过将多个表格层叠在一起而产生的错觉。
因此,为了满足您对用户能够 select 在免费时段进行 20 分钟约会的要求,我可以看到两个主要选项。第一个是我通常会推荐的,使用标准的 fullCalendar 功能。第二个更像是你所要求的,但我认为它过于复杂了。
1) 此选项只是将日历设置为 20 分钟的时隙持续时间,然后有代码阻止用户 select 使用更长的时间(他们不能 select由于 slotDuration
设置,周期更短。这意味着他们可以点击任何空的 space 一次,它将知道在该位置创建一个正确长度的事件。不允许用户select 任何已存在事件的插槽。(P.S。我预计在现实中您需要在添加事件之前收集更多数据,但为了演示它会立即添加一个事件。)
document.addEventListener("DOMContentLoaded", function() {
var Calendar = FullCalendar.Calendar;
var calendarEl = document.getElementById("calendar");
var calendar = new Calendar(calendarEl, {
plugins: ["timeGrid", "interaction"],
header: {
left: "prev,next today",
center: "title",
right: "timeGridFourDay"
},
defaultView: "timeGridFourDay",
views: {
timeGridFourDay: {
type: "timeGrid",
duration: { days: 4 },
buttonText: "4 day"
}
},
slotLabelFormat: {
hour: "numeric",
minute: "2-digit",
omitZeroMinute: true,
meridiem: "short"
},
allDaySlot: false,
firstDay: 1,
minTime: "08:00:00",
maxTime: "20:00:00",
contentHeight: "auto",
slotDuration: "00:20:00",
selectable: true,
select: function(info) {
//console.log(info);
calendar.addEvent({ "title": "Test", start: info.start, end: info.end })
calendar.unselect();
},
selectOverlap: false,
selectAllow: function(selectInfo) {
var stM = moment(selectInfo.start);
var enM = moment(selectInfo.end);
var diff = enM.diff(stM, "minutes");
console.log(diff);
if (diff > 20)
{
return false;
}
return true;
},
events: [
{ "title": "Existing event", "start": "2019-08-08 10:00", "end": "2019-08-08 10:20"},
{ "title": "Existing event", "start": "2019-08-08 13:20", "end": "2019-08-08 13:40"},
]
});
calendar.render();
});
演示:https://codepen.io/ADyson82/pen/aeqJQg
2) 此选项更接近您想要的 UI(来自您的第二个屏幕截图),但实现起来有点复杂。我个人也认为它会让您的日历看起来很混乱,并且更难看到空闲和忙碌的位置,但最终取决于您想要如何实现它。这通过添加第二个事件源来实现,其中包含所有当前空闲插槽的列表。然后这些用于在其中心显示每个空闲插槽的开始时间。它们的颜色与现有事件不同(表示忙时隙),因此更容易区分。
当然,这需要您使用服务器端代码计算数据库中所有当前空闲的插槽,并使用该信息填充第二个事件源。 (在演示中,空闲插槽数据是静态的,但当然这在实际应用程序中是行不通的。)
document.addEventListener("DOMContentLoaded", function() {
var Calendar = FullCalendar.Calendar;
var calendarEl = document.getElementById("calendar");
var calendar = new Calendar(calendarEl, {
plugins: ["timeGrid", "interaction"],
header: {
left: "prev,next today",
center: "title",
right: "timeGridFourDay"
},
defaultView: "timeGridFourDay",
views: {
timeGridFourDay: {
type: "timeGrid",
duration: { days: 4 },
buttonText: "4 day"
}
},
slotLabelFormat: {
hour: "numeric",
minute: "2-digit",
omitZeroMinute: true,
meridiem: "short"
},
allDaySlot: false,
firstDay: 1,
minTime: "08:00:00",
maxTime: "20:00:00",
contentHeight: "auto",
slotDuration: "00:20:00",
displayEventTime: false,
eventClick: function(info) {
if (info.event.extendedProps.type == "free") {
calendar.addEvent({
title: "Test",
start: info.event.start,
end: info.event.end
});
info.event.remove(); //delete the "free slot" event
}
},
eventSources: [
{
id: "busy",
events: [
{
title: "Existing event",
start: "2019-08-08 10:00",
end: "2019-08-08 10:20"
},
{
title: "Existing event",
start: "2019-08-08 13:20",
end: "2019-08-08 13:40"
}
]
},
{
id: "free",
backgroundColor: "green",
events: [
{
title: "08:00",
start: "2019-08-08 08:00",
end: "2019-08-08 08:20",
type: "free"
},
{
title: "08:20",
start: "2019-08-08 08:20",
end: "2019-08-08 08:40",
type: "free"
},
{
title: "08:40",
start: "2019-08-08 08:40",
end: "2019-08-08 09:00",
type: "free"
},
{
title: "09:00",
start: "2019-08-08 09:00",
end: "2019-08-08 09:20",
type: "free"
},
{
title: "09:20",
start: "2019-08-08 09:20",
end: "2019-08-08 09:40",
type: "free"
},
{
title: "09:40",
start: "2019-08-08 09:40",
end: "2019-08-08 10:00",
type: "free"
},
{
title: "10:20",
start: "2019-08-08 10:20",
end: "2019-08-08 10:40",
type: "free"
},
{
title: "10:40",
start: "2019-08-08 10:40",
end: "2019-08-08 11:00",
type: "free"
},
]
}
]
});
calendar.render();
});
对于这个演示,我只创建了几个 "free" 插槽(因为创建它们很乏味),但希望你能了解它开始时的样子。日历。当然,您可以再次根据您的要求修改 CSS。
演示:https://codepen.io/ADyson82/pen/JgpNEX
(您当然可以进一步修改 CSS 使其看起来更像您想要的外观。)
附录:这是 OP 的最终版本,适用于对最终产品感兴趣的任何人 - 基于对上述建议的考虑:https://codepen.io/hugo-trial/pen/rXdajv