本文示範如何結合 PHP 後端與 JavaScript 前端,從 MySQL 資料庫讀取分類資料,實作三級下拉選單聯動(省/市/區、分類/子分類/品牌等常見場景),包含遞迴樹狀選單與 AJAX 非同步載入兩種架構。
CREATE TABLE `menu` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(50) NOT NULL COMMENT '選單名稱', `parent_id` INT DEFAULT 0 COMMENT '父層 ID,0 為頂層', `url` VARCHAR(255) DEFAULT '' COMMENT '連結網址', `sort` INT DEFAULT 0 COMMENT '排序權重' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
這個版本一次載入所有資料,透過 PHP 遞迴產生巢狀 HTML,再用 JS 控制展開/收合。
<?php
function showTreeMenu($conn, $result, $layer = 1) {
$numRows = mysqli_num_rows($result);
if ($numRows === 0) return;
echo "![]() | ";
echo "{$row['name']} | "; } else { echo "![]() | ";
echo "" . ($row['url'] ? "{$row['name']}" : $row['name']) . " | "; } echo "
<script>
function showMenu(menuId) {
const el = document.getElementById(menuId);
if (el) el.style.display = (el.style.display === 'none') ? '' : 'none';
}
</script>
避免一次載入龐大資料,改為使用者點選時才向後端請求下一層資料。
<select id="level1" name="level1"></select>
<select id="level2" name="level2" disabled></select>
<select id="level3" name="level3" disabled></select>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$('#level1').on('change', function() {
const val = $(this).val();
$('#level2, #level3').html('').prop('disabled', true);
if (!val) return;
$.getJSON('api_get_children.php', {parent_id: val}, function(data) {
$.each(data, function(i, item) {
$('#level2').append(``);
});
$('#level2').prop('disabled', false);
});
});
$('#level2').on('change', function() {
const val = $(this).val();
$('#level3').html('').prop('disabled', true);
if (!val) return;
$.getJSON('api_get_children.php', {parent_id: val}, function(data) {
$.each(data, function(i, item) {
$('#level3').append(``);
});
$('#level3').prop('disabled', false);
});
});
</script>
<?php
header('Content-Type: application/json; charset=utf-8');
$conn = mysqli_connect("localhost", "root", "123456", "menu");
mysqli_set_charset($conn, "utf8");
$parentId = isset($_GET['parent_id']) ? (int)$_GET['parent_id'] : 0;
$sql = "SELECT id, name FROM menu WHERE parent_id = $parentId ORDER BY sort";
$result = mysqli_query($conn, $sql);
$data = [];
while ($row = mysqli_fetch_assoc($result)) {
$data[] = $row;
}
echo json_encode($data, JSON_UNESCAPED_UNICODE);
?>