數據結構
<?php
$data = [
(object)['titulo' => 'Ford', 'valor' => 'opcion1'],
(object)['titulo' => 'Peugeot', 'valor' => 'opcion2'],
(object)['titulo' => 'Chevrolet','valor' => 'opcion3'],
(object)['titulo' => 'Volkswagen','valor' => 'opcion4'],
];
// 也可以是關聯數組:
$data = [
['titulo' => 'Ford', 'valor' => 'ford'],
['titulo' => 'Peugeot', 'valor' => 'peugeot'],
];
?>
模板中生成 <select>
<select class="select_brand" name="brand" onchange="onChangeBrand(this)">
<option value="" selected disabled>請選擇品牌</option>
<?php foreach ($data as $item): ?>
<option value="<?= htmlspecialchars($item->valor ?? $item['valor']) ?>">
<?= htmlspecialchars($item->titulo ?? $item['titulo']) ?>
</option>
<?php endforeach; ?>
</select>
前端聯動:品牌選中 → 載入車型
<script>
function onChangeBrand(select) {
const brandId = select.value;
if (!brandId) return;
// 1. 顯示載入狀態
const modelSelect = document.querySelector('select[name="model"]');
modelSelect.innerHTML = '';
modelSelect.disabled = true;
// 2. AJAX 獲取車型
fetch(`/api/models?brand_id=${encodeURIComponent(brandId)}`)
.then(r => r.json())
.then(list => {
modelSelect.innerHTML = '' +
list.map(m => ``).join('');
modelSelect.disabled = false;
})
.catch(() => {
modelSelect.innerHTML = '';
modelSelect.disabled = false;
});
}
</script>
後端 API 範例(PDO)
<?php
// /api/models.php
header('Content-Type: application/json; charset=utf-8');
$pdo = new PDO($dsn, $user, $pass);
$brandId = $_GET['brand_id'] ?? '';
$stmt = $pdo->prepare("SELECT id, name FROM models WHERE brand_id = ? AND status = 1");
$stmt->execute([$brandId]);
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
?>
進階:分組選單 <optgroup>
<?php
$grouped = [
'國產品牌' => [
['titulo' => '比亞迪', 'valor' => 'byd'],
['titulo' => '吉利', 'valor' => 'geely'],
],
'合資品牌' => [
['titulo' => '大眾', 'valor' => 'vw'],
['titulo' => '豐田', 'valor' => 'toyota'],
],
];
?>
<select name="brand">
<?php foreach ($grouped as $group => $items): ?>
<optgroup label="<?= htmlspecialchars($group) ?>">
<?php foreach ($items as $item): ?>
<option value="<?= htmlspecialchars($item['valor']) ?>">
<?= htmlspecialchars($item['titulo']) ?>
</option>
<?php endforeach; ?>
</optgroup>
<?php endforeach; ?>
</select>
安全與最佳實踐
| 項目 | 做法 |
| XSS 防護 | 所有輸出經 htmlspecialchars() |
| 空值處理 | 提供「請選擇」佔位 option,value 為空 |
| 數據量大 | 改用 AJAX 搜索型下拉(Select2/Typeahead),勿一次性渲染千條 |
| 緩存 | 品牌列表極少變動,Redis 緩存或靜態文件 include |
| 無障礙 | <label for="brand"> 關聯,aria-label 補充 |