
本文详解 laravel 8(兼容 php 8)中 fullcalendar 数据不渲染的根本原因,涵盖事件数据格式校验、ajax 配置冲突修复、时间字段标准化处理及安全初始化实践。
本文详解 laravel 8(兼容 php 8)中 fullcalendar 数据不渲染的根本原因,涵盖事件数据格式校验、ajax 配置冲突修复、时间字段标准化处理及安全初始化实践。
在将 Laravel 应用从 PHP 7 升级至 PHP 8 后,许多开发者遇到 FullCalendar 事件无法显示的问题——数据库能正常查询,视图也成功传入 $data,但日历界面始终空白。这并非 PHP 版本兼容性 bug,而是由事件数据结构不满足 FullCalendar v3.x 要求、重复/冲突的 events 配置项以及时间格式未严格遵循 ISO 8601 标准共同导致。
? 根本问题定位
原代码中存在两个关键错误:
-
events 属性被重复定义:
events: "{{ route('kkalender.index') }}", // ❌ 错误:字符串 URL 不会被自动解析为事件数组 // ... 后续又定义了: events: [ @foreach ($data as $value) { ... } ], // ✅ 正确:内联渲染 JSON 数组FullCalendar 会以后声明的 events 覆盖前一个。由于第一行传入的是字符串路径而非有效事件源(如 AJAX endpoint),而第二行才是真实数据,但因语法或上下文错误(如未转义引号、XSS 过滤干扰),实际渲染失败。
-
事件对象缺少必需字段:
FullCalendar v3.x 要求每个事件必须包含 id、title、start(必填)、end(可选,但推荐提供)。原代码中:- 缺失 id: '{{ $value->id }}' → 导致事件无法被识别、拖拽、删除;
- 使用 dari/sampai 字段名而非标准 start/end → FullCalendar 忽略非标准键;
- allDay 未显式传递布尔值,仅依赖 eventRender 动态修正,不可靠。
✅ 正确实现方案(Laravel 8 + PHP 8 兼容)
1. 控制器:确保数据结构规范
// app/Http/Controllers/K_JadwalController.php
public function index()
{
// 显式选择必要字段,并确保时间格式为 'Y-m-d H:i:s'
$events = K_Jadwal::select('id', 'kategori as title', 'dari as start', 'sampai as end')
->whereNotNull('dari')
->get()
->map(function ($event) {
// 强制转换为 Carbon 实例并格式化,避免时区/字符串解析异常
$event->start = \Carbon\Carbon::parse($event->start)->format('Y-m-d\TH:i:s');
$event->end = $event->end ? \Carbon\Carbon::parse($event->end)->format('Y-m-d\TH:i:s') : null;
return $event;
});
return view('kkalender.index', compact('events'));
}2. Blade 模板:安全内联渲染事件数组
{{-- resources/views/kkalender/index.blade.php --}}
<script>
$(document).ready(function() {
var bg_task = ["bg-teal", "bg-purple", "bg-warning", "bg-muted", "bg-primary", "bg-success", "bg-brown", "bg-pink", "bg-info"];
$('#calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
editable: true,
selectable: true,
defaultView: 'month',
// ✅ 关键:直接使用内联 JSON,避免 AJAX 冲突
events: [
@foreach($events as $e)
{
id: {{ $e->id }},
title: "{{ addslashes($e->title) }}",
start: "{{ $e->start }}",
end: {{ $e->end ? '"' . $e->end . '"' : 'null' }},
className: bg_task[Math.floor(Math.random() * bg_task.length)]
}@if(!$loop->last),@endif
@endforeach
],
eventClick: function(event) {
if (confirm('确定删除该日程?')) {
$.post("{{ route('kkalender.fullcalenderAjax') }}", {
_token: "{{ csrf_token() }}",
id: event.id,
type: 'delete'
}).done(function() {
$('#calendar').fullCalendar('removeEvents', event.id);
toastr.success('删除成功!');
});
}
}
});
});
</script>⚠️ 注意事项:
- 使用 addslashes() 防止标题中的单引号破坏 JS 字符串;
- @if(!$loop->last),@endif 确保 JSON 数组末尾无多余逗号(IE 兼容);
- 时间格式必须为 Y-m-d\TH:i:s(如 2024-05-20T09:00:00),\T 是 ISO 8601 标准分隔符,不可省略。
3. 路由与资源管理(推荐 Resource 路由)
// routes/web.php
Route::resource('kkalender', K_JadwalController::class)->except(['show']);
Route::post('kkalender/fullcalenderAjax', [K_JadwalController::class, 'ajax'])->name('kkalender.fullcalenderAjax');4. 前端资源加载优化(避免 CDN 冲突)
移除混合 CDN 加载(如同时引入 cdnjs 和本地 fullcalendar.min.js),统一使用本地资源:
<!-- 仅保留一组 -->
<link rel="stylesheet" href="{{ asset('assets/plugins/fullcalendar/css/fullcalendar.min.css') }}">
<script src="{{ asset('assets/plugins/moment/moment.min.js') }}"></script>
<script src="{{ asset('assets/plugins/fullcalendar/js/fullcalendar.min.js') }}"></script>? 验证与调试技巧
- 在浏览器控制台执行 console.log({{ $events->toJson() }}),确认输出为合法 JSON 数组;
- 检查 Network 面板,确保无 419/500 报错,CSRF Token 已正确注入;
- 使用 fullCalendar('clientEvents') 查看当前渲染的事件列表;
- 若仍为空,临时将 events 设为静态测试数据:
events: [{ id:1, title:'Test', start:'2024-05-20T10:00:00' }]
✅ 总结
Laravel 8 + PHP 8 下 FullCalendar 事件不显示,本质是数据契约未对齐。解决方案核心在于:
① 控制器返回严格符合 id/title/start/end 结构的集合;
② Blade 中安全内联渲染(非 AJAX 请求);
③ 时间字段强制 ISO 8601 格式(Y-m-d\TH:i:s);
④ 移除重复 events 配置,杜绝覆盖逻辑。
遵循以上步骤,即可在 PHP 8 环境下稳定运行 FullCalendar,无需降级或更换插件。


















