無限分類、選單導航、組織架構、評論回覆等層級不固定的資料結構,常以「遞迴」或「引用陣列」兩種方式輸出樹狀 HTML。
CREATE TABLE `tree` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(100) NOT NULL,
`parent` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '父節點 ID,0 為頂層',
`ischild` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否有子節點',
`sort` INT UNSIGNED NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
<?php
header('Content-Type: text/html; charset=utf-8');
$pdo = new PDO('mysql:host=localhost;dbname=wz;charset=utf8', 'root', '123456');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
/**
* 遞迴輸出節點
* @param PDO $pdo
* @param int $parentId
* @param int $level 階層深度,用於縮排
*/
function renderTree($pdo, $parentId = 0, $level = 0) {
$stmt = $pdo->prepare('SELECT id, name, ischild FROM tree WHERE parent = ? ORDER BY sort, id');
$stmt->execute([$parentId]);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!$rows) return;
$indent = str_repeat(' ', $level);
foreach ($rows as $row) {
$id = $row['id'];
$name = htmlspecialchars($row['name']);
$hasChild = (bool)$row['ischild'];
// 展開/收合連結
$toggle = $hasChild
? "[+] "
: '- ';
echo "{$indent}{$toggle}{$name}\n";
if ($hasChild) {
// 子節點預設隱藏
echo "\n";
}
}
}
// 輸出頂層節點
renderTree($pdo);
?>
<script>
function toggleNode(nodeId) {
const childId = nodeId.replace('node_', 'child_');
const childDiv = document.getElementById(childId);
const link = document.querySelector(`#${nodeId} a`);
if (!childDiv) return;
if (childDiv.style.display === 'none') {
childDiv.style.display = 'block';
link.textContent = '[-]';
} else {
childDiv.style.display = 'none';
link.textContent = '[+]';
}
}
</script>
<style>
.tree-node { cursor: pointer; }
.tree-children { margin-left: 1.5em; }
</style>
SELECT id, name, parent FROM tree 全部撈出,PHP 端用引用陣列組裝樹,避免 N+1 查詢。function buildTreeArray($rows) {
$tree = [];
$ref = [];
foreach ($rows as $row) {
$id = $row['id'];
$ref[$id] = &$row;
$row['children'] = [];
}
foreach ($rows as $row) {
$pid = $row['parent'];
if ($pid == 0 || !isset($ref[$pid])) {
$tree[] = &$row;
} else {
$ref[$pid]['children'][] = &$row;
}
}
return $tree;
}
此法只需一次查詢,適合大資料集,再配合模板引擎遞迴輸出 HTML。