本文提供一個功能完整的 Calendar 類別,支援年月導航、當前日期高亮、表單提交切換月份、表格式輸出,適合嵌入後台管理、活動系統、預約平台等場景。
<?php
class Calendar {
private $year, $month, $day;
private $weekLabels = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'];
private $monthLabels = [
'01'=>'一月','02'=>'二月','03'=>'三月','04'=>'四月',
'05'=>'五月','06'=>'六月','07'=>'七月','08'=>'八月',
'09'=>'九月','10'=>'十月','11'=>'十一月','12'=>'十二月'
];
public function setYear($y) { $this->year = $y; }
public function getYear() { return $this->year; }
public function setMonth($m) { $this->month = sprintf('%02d', $m); }
public function getMonth() { return $this->month; }
public function setDay($d) { $this->day = sprintf('%02d', $d); }
public function getDay() { return $this->day; }
// 取得指定日期的星期幾 (0=日 .. 6=六)
private function getWeek($y, $m, $d) {
return date('w', mktime(0,0,0,$m,$d,$y));
}
// 環境初始化:處理 POST 參數或預設為當月
private function initEnv() {
$this->setYear(isset($_POST['year']) ? (int)$_POST['year'] : date('Y'));
$this->setMonth(isset($_POST['month']) ? $_POST['month'] : date('m'));
$this->setDay(date('d'));
}
// 輸出完整月曆 HTML
public function render() {
$this->initEnv();
$y = $this->getYear();
$m = $this->getMonth();
$d = $this->getDay();
$firstWeek = $this->getWeek($y, $m, 1); // 1號星期幾
$daysInMonth = date('t', mktime(0,0,0,$m,1,$y)); // 本月天數
$html = '<div class="calendar">';
$html .= '<form method="post" class="cal-nav">';
$html .= '<select name="month" onchange="this.form.submit()">';
foreach ($this->monthLabels as $num => $label) {
$sel = ($num === $m) ? ' selected' : '';
$html .= "<option value=\"$num\"$sel>$label</option>";
}
$html .= '</select> ';
$html .= '<select name="year" onchange="this.form.submit()">';
for ($yr = $y - 10; $yr <= $y + 10; $yr++) {
if ($yr < 1970 || $yr > 2037) continue;
$sel = ($yr == $y) ? ' selected' : '';
$html .= "<option value=\"$yr\"$sel>$yr</option>";
}
$html .= '</select></form>';
$html .= '<table class="cal-grid"><thead><tr>';
foreach ($this->weekLabels as $w) $html .= "<th>$w</th>";
$html .= '</tr></thead><tbody><tr>';
// 1號前的空格
for ($i = 0; $i < $firstWeek; $i++) $html .= '<td></td>';
for ($day = 1; $day <= $daysInMonth; $day++) {
$week = $this->getWeek($y, $m, $day);
if ($week === 0 && $day !== 1) $html .= '</tr><tr>';
$class = ($day == (int)$d) ? ' class="today"' : '';
$html .= "<td$class>$day</td>";
}
$html .= '</tr></tbody></table></div>';
echo $html;
}
}
// 使用範例
$cal = new Calendar();
$cal->render();
?>
.calendar { font-family: sans-serif; max-width: 400px; margin: 1rem auto; }
.cal-nav { text-align: center; margin-bottom: 0.5rem; }
.cal-nav select { padding: 0.3rem; font-size: 0.9rem; }
.cal-grid { width: 100%; border-collapse: collapse; }
.cal-grid th, .cal-grid td { width: 14.28%; text-align: center; padding: 0.4rem; border: 1px solid #ddd; }
.cal-grid th { background: #f0f0f0; font-weight: 600; }
.cal-grid .today { background: #ffeb3b; font-weight: bold; border-color: #fbc02d; }
.cal-grid td:empty { background: #fafafa; }
| 功能 | 實作方向 | |
|---|---|---|
| 事件/行程標記 | 資料表儲存 date, title, url,render() 時查詢當月事件,在 | 內追加 <a href="..." class="event">標題</a> |
| AJAX 切換月份 | 移除 onchange="this.form.submit()",改用 fetch() 取得片段 HTML 替換容器 | |
| 日期範圍選取 | 加入 data-date 屬性,JS 監聽點擊實現雙擊選範圍 | |
| 農曆/節氣顯示 | 引入 ChineseCalendar 庫(如 php-chinese-calendar)轉換 | |
| 多語系 | 將 $weekLabels、$monthLabels 改為從語系檔載入 |
若需拖曳排程、月/週/日視圖切換、Google Calendar 同步、響應式設計,建議直接整合 FullCalendar (JavaScript) + 後端 API 提供 JSON 事件資料,前後端分離架構更靈活。
此 Calendar 類別適合輕量級、無前端框架、快速內嵌 PHP 頁面的場景。