You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 9中用Carbon生成日历:无事件日期重复问题修正

问题修正方案

你的日历出现重复渲染的核心问题是:每个日期会遍历所有事件,若日期有事件,输出带事件的节点后仍会继续遍历剩余事件,遇到不匹配事件时会重复输出无事件节点;错误的循环逻辑也导致无事件日期出现多次渲染。

修正思路

  1. 先将数据库查询到的事件按event_date分组,快速定位某一天的所有事件,避免遍历全部事件
  2. 对每个日期仅做一次判断:是否存在对应事件,然后输出一次节点,彻底解决重复渲染问题

修正后的控制器代码

$date = empty($date) ? Carbon::now() : Carbon::createFromDate($date);
$startOfCalendar = $date->copy()->firstOfMonth()->startOfWeek(Carbon::SUNDAY);
$endOfCalendar = $date->copy()->lastOfMonth()->endOfWeek(Carbon::SATURDAY);

$html = '<div class="calendar">';

$html .= '<div class="month-year">';
$html .= '<span class="month">' . $date->format('M') . '</span>';
$html .= '<span class="year">' . $date->format('Y') . '</span>';
$html .= '</div>';

$html .= '<div class="days">';

$dayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
foreach ($dayLabels as $dayLabel)
{
    $html .= '<span class="day-label">' . $dayLabel . '</span>';
}

// 将事件按日期分组,方便快速查找
$eventsByDate = CalendarEvents::where("event_date", ">=", $startOfCalendar->toDateString())
    ->get()
    ->groupBy('event_date');

while($startOfCalendar <= $endOfCalendar)
{
    $currentDateStr = $startOfCalendar->toDateString();
    $extraClass = $startOfCalendar->format('m') != $date->format('m') ? 'dull' : '';
    $extraClass .= $startOfCalendar->isToday() ? ' today' : '';
    
    // 检查当前日期是否有事件
    if($eventsByDate->has($currentDateStr)) {
        // 若有事件,遍历输出所有事件(支持同一天多个事件)
        foreach($eventsByDate[$currentDateStr] as $event) {
            $html .= '<span class="day flip' . $extraClass . '"><span class="content">' . $startOfCalendar->format('j').'|'.$event->event_name. '</span></span>';
        }
    } else {
        // 无事件则输出普通日期节点
        $html .= '<span class="day' . $extraClass . '"><span class="content">' . $startOfCalendar->format('j') . '</span></span>';
    }

    $startOfCalendar->addDay();
}
$html .= '</div></div>';

关键优化点

  • 使用groupBy('event_date')将事件按日期分组,避免每个日期遍历全部事件,提升性能同时解决重复渲染
  • 每个日期仅做一次存在性判断,输出对应节点(若同一天有多个事件,可遍历输出所有事件,也可合并显示)
  • 使用Carbon的toDateString()方法直接获取标准日期字符串,避免date('Y-m-d', strtotime($startOfCalendar))的冗余转换

内容的提问来源于stack exchange,提问作者Muntashir Are Rahi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 10:50:22