html二级联动数据库
- 行业动态
- 2025-05-05
- 1
二级联动数据库
二级联动是指页面上两个下拉框(Select)之间存在关联关系,当用户在前一个下拉框中选择某项时,后一个下拉框的选项会根据前一个的选择动态更新,这种效果常用于省市县选择、商品分类筛选等场景,实现二级联动通常需要结合前端技术(HTML/CSS/JavaScript)和后端技术(PHP/MySQL)进行数据库交互。
数据库设计
数据表结构
假设实现“省份-城市”二级联动,需设计两张表:
| 表名 | 字段名 | 类型 | 说明 |
|————|—————-|—————|————————–|
| provinces | id (主键) | INT AUTO_INCREMENT | 省份唯一标识 |
| provinces | name | VARCHAR(50) | 省份名称 |
| cities | id (主键) | INT AUTO_INCREMENT | 城市唯一标识 |
| cities | province_id | INT | 外键,关联provinces.id |
| cities | name | VARCHAR(50) | 城市名称 |
示例数据
provinces表:
| id | name |
|—-|———-|
| 1 | 北京市 |
| 2 | 上海市 |
| 3 | 广东省 |
cities表:
| id | province_id | name |
|—-|————-|———|
| 1 | 1 | 北京市 |
| 2 | 1 | 朝阳区 |
| 3 | 2 | 上海市 |
| 4 | 2 | 徐汇区 |
| 5 | 3 | 广州市 |
| 6 | 3 | 深圳市 |
前端页面实现
HTML结构
<select id="province"> <option value="">请选择省份</option> <!-动态加载省份数据 --> </select> <select id="city" disabled> <option value="">请选择城市</option> <!-动态加载城市数据 --> </select>
JavaScript逻辑
// 初始化省份下拉框 function loadProvinces() { // 通过AJAX请求省份数据(示例用静态数据) const provinces = [ { id: 1, name: '北京市' }, { id: 2, name: '上海市' }, { id: 3, name: '广东省' } ]; const provinceSelect = document.getElementById('province'); provinces.forEach(p => { const option = document.createElement('option'); option.value = p.id; option.text = p.name; provinceSelect.appendChild(option); }); } // 根据省份加载城市 function loadCities(provinceId) { const citySelect = document.getElementById('city'); citySelect.disabled = false; // 启用城市下拉框 citySelect.innerHTML = '<option value="">请选择城市</option>'; // 清空旧数据 // 通过AJAX请求城市数据(示例用静态数据) const cities = [ { id: 1, name: '北京市', province_id: 1 }, { id: 2, name: '朝阳区', province_id: 1 }, { id: 3, name: '上海市', province_id: 2 }, { id: 4, name: '徐汇区', province_id: 2 }, { id: 5, name: '广州市', province_id: 3 }, { id: 6, name: '深圳市', province_id: 3 } ]; const filteredCities = cities.filter(c => c.province_id === provinceId); filteredCities.forEach(c => { const option = document.createElement('option'); option.value = c.id; option.text = c.name; citySelect.appendChild(option); }); } // 绑定事件 document.getElementById('province').addEventListener('change', function() { const provinceId = this.value; if (provinceId) { loadCities(provinceId); } else { document.getElementById('city').innerHTML = '<option value="">请选择城市</option>'; document.getElementById('city').disabled = true; } }); // 初始化页面 loadProvinces();
后端数据接口(PHP+MySQL)
获取省份列表
// getProvinces.php <?php header('Content-Type: application/json'); $servername = "localhost"; $username = "root"; $password = ""; $dbname = "test"; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die(json_encode(['error' => '数据库连接失败'])); } $sql = "SELECT id, name FROM provinces"; $result = $conn->query($sql); $data = []; if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { $data[] = $row; } } echo json_encode($data); $conn->close();
根据省份ID获取城市列表
// getCities.php <?php header('Content-Type: application/json'); $servername = "localhost"; $username = "root"; $password = ""; $dbname = "test"; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { die(json_encode(['error' => '数据库连接失败'])); } $province_id = intval($_GET['province_id']); // 获取前端传递的省份ID $sql = "SELECT id, name FROM cities WHERE province_id = ?"; $stmt = $conn->prepare($sql); $stmt->bind_param("i", $province_id); $stmt->execute(); $result = $stmt->get_result(); $data = []; if ($result->num_rows > 0) { while ($row = $result->fetch_assoc()) { $data[] = $row; } } echo json_encode($data); $stmt->close(); $conn->close();
前后端数据交互(AJAX)
修改前端代码(使用AJAX请求后端接口)
// 初始化省份下拉框(通过AJAX请求后端数据) function loadProvinces() { fetch('getProvinces.php') .then(response => response.json()) .then(data => { const provinceSelect = document.getElementById('province'); data.forEach(p => { const option = document.createElement('option'); option.value = p.id; option.text = p.name; provinceSelect.appendChild(option); }); }) .catch(error => console.error('Error:', error)); } // 根据省份加载城市(通过AJAX请求后端数据) function loadCities(provinceId) { fetch(`getCities.php?province_id=${provinceId}`) .then(response => response.json()) .then(data => { const citySelect = document.getElementById('city'); citySelect.disabled = false; // 启用城市下拉框 citySelect.innerHTML = '<option value="">请选择城市</option>'; // 清空旧数据 data.forEach(c => { const option = document.createElement('option'); option.value = c.id; option.text = c.name; citySelect.appendChild(option); }); }) .catch(error => console.error('Error:', error)); }
相关问题与解答
问题1:如何防止SQL注入?
解答:
在后端代码中,使用Prepared Statements
(如PHP的$stmt->prepare()
)代替直接拼接SQL语句。
$stmt = $conn->prepare("SELECT id, name FROM cities WHERE province_id = ?"); $stmt->bind_param("i", $province_id); // 将变量绑定到占位符 $stmt->execute();
这种方式可以避免用户输入反面SQL代码,确保安全性。
问题2:如果城市数据较多,如何优化性能?
解答:
- 数据库层面:
- 为
cities
表的province_id
字段添加索引,加快查询速度。 - 分页加载城市数据(如每次只加载前100条)。
- 为
- 前端层面:
- 缓存已请求过的城市数据,避免重复请求。
- 使用
async/await
优化异步代码逻辑,减少阻塞。
- 后端层面:
- 使用
LIMIT
限制单次返回的数据量,SELECT id, name FROM cities WHERE province_id = ? LIMIT 1
- 使用