首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實作動態月曆:從基礎算法到前端渲染完整指南

     編輯:PHP 相關知識

月曆功能看似簡單,實則涉及日期計算、閏年判斷、週期對齊等核心邏輯。本文從零構建一個可翻頁、高亮今日、支援任意年月跳轉的動態月曆,適合學習 PHP 日期處理與前後端分離思維。

核心 PHP 邏輯

<?php
// 1. 解析請求參數(格式:YYYYMM)
$ym = isset($_GET['ym']) ? (int)$_GET['ym'] : 0;

if ($ym) {
    $year  = (int)substr($ym, 0, 4);
    $month = (int)substr($ym, 4, 2);
    // 驗證合法性
    if ($month < 1 || $month > 12) $ym = 0;
    $timestamp = mktime(0, 0, 0, $month, 1, $year);
} else {
    $timestamp = time(); // 預設當月
}

// 2. 核心日期資訊提取
$year  = (int)date('Y', $timestamp);
$month = (int)date('m', $timestamp);
$day   = (int)date('d', $timestamp); // 僅當月有效

// 3. 導航月份計算
$prevYm = date('Ym', strtotime('-1 month', $timestamp));
$nextYm = date('Ym', strtotime('+1 month', $timestamp));

// 4. 當月關鍵數值
$totalDays = (int)date('t', $timestamp);     // 當月總天數
$firstWeek = (int)date('w', mktime(0,0,0,$month,1,$year)); // 1號是週幾(0=週日)
$lastWeek  = (int)date('w', mktime(0,0,0,$month,$totalDays,$year)); // 最後一天週幾

// 5. 空白格計算
$leadingBlanks = $firstWeek;                    // 前導空白
$trailingBlanks = 6 - $lastWeek;                // 尾部空白
?>

HTML + CSS 模板(嵌入 PHP 輸出)

<!DOCTYPE html>
<html><head><meta charset="utf-8">
<style>
.cal-wrap {width:280px;font-family:sans-serif;margin:20px auto;}
.cal-header {display:flex;justify-content:space-between;align-items:center;
    background:#333;color:#fff;padding:10px;border-radius:8px 8px 0 0;}
.cal-header a {color:#fff;text-decoration:none;font-weight:bold;}
.cal-title {font-size:1.1rem;}
table {width:100%;border-collapse:collapse;background:#fff;}
th, td {height:36px;text-align:center;font-size:0.9rem;}
th {background:#f5f5f5;color:#666;font-weight:600;}
td {border:1px solid #eee;transition:background .2s;}
td:hover {background:#e8f4fd;}
.today {background:#ff6b35!important;color:#fff;font-weight:bold;border-radius:50%;}
.other-month {color:#ccc;background:#fafafa;}
.weekend {color:#e74c3c;}
</style></head><body>

<div class="cal-wrap">
    <div class="cal-header">
        <a href="?ym=<?=$prevYm?>" title="上月">‹</a>
        <span class="cal-title"><?=$year?>年<?=$month?>月</span>
        <a href="?ym=<?=$nextYm?>" title="下月">›</a>
    </div>
    <table>
        <thead><tr>
            <th class="weekend">日</th><th>一</th><th>二</th><th>三</th>
            <th>四</th><th>五</th><th class="weekend">六</th>
        </tr></thead>
        <tbody>
            <tr>
                <?php 
                // 前導空白
                for ($i = 0; $i < $leadingBlanks; $i++) 
                    echo '<td class="other-month">&nbsp;</td>';
                
                // 日期迴圈
                for ($d = 1; $d <= $totalDays; $d++) {
                    $classes = [];
                    if ($d === $day && $ym !== 0) $classes[] = 'today'; // 僅當月高亮今日
                    if (($leadingBlanks + $d - 1) % 7 === 0) $classes[] = 'weekend';
                    if (($leadingBlanks + $d) % 7 === 0) $classes[] = 'weekend';
                    $classAttr = $classes ? ' class="' . implode(' ', $classes) . '"' : '';
                    
                    echo "<td$classAttr>$d</td>";
                    
                    // 換行邏輯
                    if (($leadingBlanks + $d) % 7 === 0 && $d < $totalDays)
                        echo '</tr><tr>';
                }
                
                // 尾部空白
                for ($i = 0; $i < $trailingBlanks; $i++)
                    echo '<td class="other-month">&nbsp;</td>';
                ?>
            </tr>
        </tbody>
    </table>
</div>
</body></html>

關鍵算法詳解

問題 解決方案
1號對齊週幾 date('w', mktime(0,0,0,月,1,年)) 返回 0(日)~6(六)
當月天數 date('t', timestamp) 自動處理閏年二月
上/下月導航 strtotime('±1 month', timestamp) 自動跨年
換行判斷 ($leadingBlanks + $d) % 7 === 0 每 7 格換行
今日高亮 僅當 $ym === 0(當月)且 $d === $day 時套用

進階擴展方向

  • 農曆/節氣顯示:引入開源庫(如 php-lunar)轉換陰曆日期
  • 行事曆事件:資料庫儲存事件,查詢當月資料後以 data-attributes 傳遞給前端
  • AJAX 無刷新翻頁:前端 fetch 請求片段 HTML,局部更新
  • 多語言支援:週名、月名國際化(IntlDateFormatter)
  • 響應式設計:CSS Grid 重構,小螢幕下堆疊顯示

常見坑點提醒

  1. strtotime('last month') 在 3/31 會回到 2/28/29,導航建議固定用 1 號時間戳計算
  2. date('w') 以週日為 0,部分歐洲習慣週一為 0,需注意國際化
  3. CSS nth-child 可替代 PHP 判斷週末樣式,但 PHP 輸出 class 更靈活
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved