傳統多級下拉選單常見於地址選擇、分類篩選等場景。本文提供一個基於 PHP 遞迴輸出 HTML、JavaScript 控制展開收合的完整實作,資料來源為 MySQL,結構清晰易於擴充。
CREATE TABLE `menu` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(50) NOT NULL COMMENT '選單名稱', `url` VARCHAR(255) DEFAULT '' COMMENT '連結網址', `parent_id` INT DEFAULT 0 COMMENT '父級ID,0為頂層', `sort` INT DEFAULT 0 COMMENT '排序權重' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
";
while ($row = mysqli_fetch_assoc($result)) {
// 檢查是否有子選單
$subSql = "SELECT 1 FROM menu WHERE parent_id = {$row['id']} LIMIT 1";
$hasChild = mysqli_num_rows(mysqli_query($conn, $subSql)) > 0;
static $menuId = 0; // 唯一 ID 產生器
$currentId = 'Menu' . $menuId++;
echo "";
// 展開/收合圖示
echo "";
echo $hasChild
? "
"
: "
";
echo " ";
// 選單文字
echo "";
if ($row['url']) {
echo "{$row['name']}";
} else {
echo $row['name'];
}
echo " ";
// 遞迴輸出子選單(初始隱藏)
if ($hasChild) {
echo "";
}
}
echo "";
}
// 執行輸出
renderTreeMenu($conn);
?>
.menu-level-1 { margin-left: 0; }
.menu-level-2 { margin-left: 20px; border-left: 1px solid #ddd; }
.menu-level-3 { margin-left: 40px; border-left: 1px solid #ddd; }
.menu-item { cursor: pointer; padding: 4px 8px; user-select: none; }
.menu-item:hover { background: #f0f0f0; }
.has-child { font-weight: bold; }
.toggle-icon { vertical-align: middle; cursor: pointer; }
<script> 變數,前端 JS 直接渲染,減少遞迴查詢tabindex、role="treeitem"、Enter/Space 觸發展開project/ ├── index.php # 主頁面,含 CSS/JS/輸出邏輯 ├── db.php # 資料庫連線設定 ├── tree_expand.gif # 展開圖示 └── tree_collapse.gif # 收合圖示
此範例採用「伺服器端遞迴輸入 + 前端事件代理」架構,邏輯分離清楚,適合中小型專案直接套用,亦可作為更複雜元件的基礎骨架。