傳統靜態菜單的痛點
- 結構固定,擴充需重寫代碼
- 層級關係硬編碼,維護困難
- 無法適應動態業務變更
資料庫設計:遞歸關聯模型
CREATE TABLE menu (
id tinyint(4) NOT NULL auto_increment,
parent_id tinyint(4) DEFAULT '0' NOT NULL,
name varchar(20),
url varchar(60),
PRIMARY KEY (id)
);
id:主鍵
parent_id:父級 ID,頂級為 0
name:顯示名稱
url:葉子節點鏈接,非葉子為空
測試數據
INSERT INTO menu VALUES
('1', '0', '人事管理', ''),
('2', '0', '通訊交流', ''),
('3', '1', '檔案管理', ''),
('4', '1', '考勤管理', 'https://localhost/personal/attendance.php'),
('5', '2', '通訊錄', ''),
('6', '2', '網絡會議', ''),
('7', '3', '新增檔案', 'https://localhost/personal/add_achive.php'),
('8', '3', '查詢檔案', 'https://localhost/personal/search_archive.php'),
('9', '3', '刪除檔案', 'https://localhost/personal/delete_archive.php'),
('10', '5', '新增通訊記錄', 'https://localhost/communication/add_address.php'),
('11', '5', '查詢通訊記錄', 'https://localhost/communication/search_address.php'),
('12', '5', '刪除通訊記錄', 'https://localhost/communication/delete_address.php'),
('13', '6', '召開會議', 'https://localhost/communication/convence_meeting.php'),
('14', '6', '會議查詢', 'https://localhost/communication/search_meeting.php');
前端交互:JavaScript 折疊控制
function ShowMenu(menuId) {
var el = document.getElementById(menuId);
if (el.style.display == "none") {
el.style.display = "";
} else {
el.style.display = "none";
}
}
樣式定義 (style.css)
TD { font-family: Verdana, 宋體; font-size: 12px; line-height: 130%; letter-spacing: 1px; }
A:link, A:visited, A:active { color: #990000; text-decoration: none; }
A:hover { color: #ff0000; text-decoration: underline; }
.Menu { color: #000000; cursor: pointer; }
核心 PHP 遞歸函數
<?php
$GLOBALS["ID"] = 1; // 全局菜單 ID 計數器
$layer = 1; // 當前層級
$conn = mysql_connect("localhost", "root", "");
mysql_select_db("work");
$sql = "select * from menu where parent_id = 0";
$result = mysql_query($sql, $conn);
if (mysql_num_rows($result) > 0) {
ShowTreeMenu($conn, $result, $layer);
}
function ShowTreeMenu($conn, $result, $layer) {
$num = mysql_num_rows($result);
echo "<table cellpadding='0' cellspacing='0' border='0'>";
for ($i = 0; $i < $num; $i++) {
$menu = mysql_fetch_array($result);
// 查詢子菜單
$subSql = "select * from menu where parent_id = $menu[id]";
$subResult = mysql_query($subSql, $conn);
$hasChild = mysql_num_rows($subResult) > 0;
echo "<tr>";
if ($hasChild) {
echo "<td width='20'><img src='folder.gif' border='0'></td>";
echo "<td class='Menu' onClick='javascript:ShowMenu(Menu" . $GLOBALS["ID"] . ");'>";
} else {
echo "<td width='20'><img src='file.gif' border='0'></td>";
echo "<td class='Menu'>";
}
// 顯示名稱或鏈接
if ($menu["url"] != "") {
echo "<a href='" . $menu["url"] . "'>" . $menu["name"] . "</a>";
} else {
echo $menu["name"];
}
echo "</td></tr>";
// 遞歸輸出子菜單
if ($hasChild) {
echo "<tr id='Menu" . $GLOBALS["ID"]++ . "' style='display:none'>";
echo "<td width='20'> </td><td>";
$layer++;
ShowTreeMenu($conn, $subResult, $layer);
$layer--;
echo "</td></tr>";
}
}
echo "</table>";
}
?>
關鍵設計亮點
- 無限級遞歸:不限制菜單深度,自適應數據結構
- 動態 ID 生成:全局計數器確保每個子菜單 DOM ID 唯一
- CSS/JS 分離:樣式與行為解耦,易於主題定制
- 圖標語義化:資料夾/文件圖標直觀標識節點類型
現代化改進建議
- 採用 PDO + 預處理語句防注入
- 前端改用 `
/- ` 語義化結構 + CSS 動畫
- 引入 AJAX 延遲加載大數據量子樹
- 增加權限控制字段,按角色動態渲染