将事件加载到完整日历



到目前为止,我一直在进行同步 ajax 调用以从数据库获取事件,然后使用从 ajax 返回的变量初始化日历(解决方案 1)。

我已经读到进行同步调用通常被认为是不好的,因为它冻结了浏览器,所以我尝试了另一个选项,将 ajax 调用直接放在 FullCalendar 日历初始化的事件数组中(解决方案 2)。这在第一次加载时提供了很好的体验,因为浏览器不会由于异步 ajax 而被锁定,并且您可以在日历构建时看到它。

但是,这有一个缺点,每次更改视图时,它都会重新呈现事件,使用户体验与第一个事件相比不太流畅。以下是我到目前为止尝试的两个解决方案的代码:

解决方案 1:

$(document).ready(function(){
$.ajax({
url: 'script.php',
type: 'POST',
async: false,
success: function(response){
json_events = response;
}
});
$('#calendar').fullCalendar({
events: JSON.parse(JSON.stringify(json_events)),
});
});

解决方案 2:

$(document).ready(function(){
$('#calendar').fullCalendar({
events: {
url: 'script.php',
type: 'POST',
success : function(response){
}
}
});
});

这个"问题"还有其他解决方案吗?对,我更喜欢解决方案 1,因为您在使用日历时不必处理事件的重新渲染,但在加载页面时不要初始冻结会很好。

编辑:脚本.php

$events = array();
$query = mysqli_query($link, "SELECT * FROM calendar");
while($fetch = mysqli_fetch_array($query,MYSQLI_ASSOC)) {
$e = array();
$e['id'] = $fetch['id'];
$e['start'] = $fetch['startdate'];
$e['end'] = $fetch['enddate'];
array_push($events, $e);
}
echo json_encode($events);

这行得通吗?(对于评论中的戴森)

events: {
url: 'script2.php',
type: 'POST',
data : {
calendar_id : calendarId
},
success : function(response){
}
}

脚本2.php

$calend_id = $_POST['calendar_id'];
$start = $_POST['start'];
$end = $_POST['end'];
$events = array();
$query = mysqli_query($link, "SELECT startdate,enddate,id FROM calendar WHERE calendar_id = '$calend_id' AND startdate >= '$start' AND enddate <= '$end'");
while($fetch = mysqli_fetch_array($query,MYSQLI_ASSOC)) {
$e = array();
$e['id'] = $fetch['id'];
$e['start'] = $fetch['startdate'];
$e['end'] = $fetch['enddate'];
array_push($events, $e);
}
echo json_encode($events);

FullCalendar 实际上希望您只加载当前视图所需的事件。这意味着您不必预先加载所有事件。想想看,一旦你的软件运行了几年,"所有事件"可能会相当大,并且会减慢日历的加载速度。此外,您必须考虑用户突然想要查看 3 年前日历的可能性有多大?这可能是一种边缘情况,因此您不需要立即使用这些事件。

FullCalendar提供了一种非常简洁的方式来自动执行此操作。请参阅此链接 https://fullcalendar.io/docs/event_data/events_json_feed/

基本上,您只需将PHP端点指定为"事件"URL,只要您遵守该链接中指定的结构,当用户更改显示的日期范围和/或视图时,它将自动下载正确的事件。

因此,在您的日历配置中:

events: "script.php"

就这么简单!FullCalendar将自动传递两个字段 - "开始"和"结束"作为获取事件的日期。所以在你的PHP中,你需要这样的东西:

$events = array();
$start = $_GET["start"];
$end = $_GET["end"];
//code to build a query with a WHERE clause specifying the start/end dates
//...
//and finally echo the resulting events
echo json_encode($events);

除非网络延迟对您来说是一个大问题,否则仅在需要时才批量下载事件是首选。此外,默认情况下设置了一个日历选项:lazyFetching: true它试图最大限度地减少所需的 ajax 调用数量 - 有关其工作原理的更多详细信息,请参阅 https://fullcalendar.io/docs/event_data/lazyFetching/。

如果您担心事件加载时的用户体验,则可以处理"加载"回调,因此您可以添加诸如"加载"微调器之类的内容或其他内容,以向用户指示他们只需要等待几秒钟即可显示事件。有关更多详细信息,请参阅 https://fullcalendar.io/docs/event_data/loading/。

这里有很多东西需要优化,所以让我们一步一步地做。

首先在你的 php 脚本中,你发出Select * from calendar但你只使用三列来生成 json 提要,所以为什么不Select id,startdate,enddate from calendar呢? 这(取决于calendar模式)将从数据库中获取更少的数据,如果您正确地完成了索引,它将为使用这些索引提供更好的机会。

其次,您可以进行某种分页,我很确定您不希望您的用户一次看到所有内容,在这种情况下,您使用SQL的LIMIT,并且OFFSET或更好的Where clause仅获取两个日期或两个日期之间的事件。

现在我们必须区分两种情况:

情况 1:我们不介意用户看到事件的过时版本

因此,也许您不介意用户查看已删除的事件,更新的事件,最重要的是,您不介意用户错过新事件。

首先要做的是在你传递给fullCalendarevents: {...}内部传递cache: true,这将激活浏览器的缓存,然后你需要更新script.php以检查Last-modified,可能还有Etag标题,检查你的表从那时起的更新,如果没有更新(没有插入/删除/更新),你只需发送一个304响应(未修改), 您可以使用任何历史记录机制来了解表在日期之间有哪些更新。

第二件事是在服务器端使用某种缓存机制来缓存数据库响应,您可以使用Redis(或 memcached 或任何其他)并构建一个后台作业,在您选择的每个时间间隔内将缓存与数据库同步。

或者您可以在数据库中制作一个物化视图,让它在每个时间间隔刷新并从该视图中进行选择,不幸的是 mysql 本身不支持它,但有 Flexviews,请参阅此处:https://mariadb.com/kb/en/mariadb/flexviews/

要做的第三件事是找到一种方法来仅发送这些更改而不是发送所有事件,这将很难,基本上您将事件作为函数而不是作为 json 提要传递给fullCalendar,然后您使用支持 mysql 的任何历史机制来了解更新,您发送它们并在客户端找到一种方法来解释这些更改并更新一些内存中对象。

如果你担心你的javascript会消耗大量内存,或者只是担心事件不适合,你可以使用IndexedDB,或者你可以使用pouchdb,因为它更简单,并且会支持不支持IndexedDB的旧浏览器。

情况2:用户必须实时查看事件更新

对于 mysql,您需要以某种方式监视对日历表的更改(例如可能是触发器),然后使用 Websockets(或基于它构建的任何技术)在客户端发生更改时推送更改,在客户端,onmessage回调需要以某种方式告诉fullCalendar更新,一种方法是更新全局数组或客户端数据库并将events作为函数传递, 另一种方法是使用fullCalendar的 updateEvent(s) 和 removeEvent(s)(显然没有插入事件,虽然 :3 )。

如果您喜欢冒险,可以使用RethinkDB,这是一个专门为您的需求制作的实时数据库,或者您可以将数据存储在像这样的事件数据库中: https://geteventstore.com/

PS:你可能混合了这两种情况,例如你不在乎Insert但你需要delete/update得到通知,然后你混合我认为:)的方法。

最新更新