当前位置:首页 > 行业动态 > 正文

html二级联动数据库

HTML二级联动基于数据库关联数据,通过AJA

二级联动数据库

二级联动是指页面上两个下拉框(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:如果城市数据较多,如何优化性能?

解答

  1. 数据库层面
    • cities表的province_id字段添加索引,加快查询速度。
    • 分页加载城市数据(如每次只加载前100条)。
  2. 前端层面
    • 缓存已请求过的城市数据,避免重复请求。
    • 使用async/await优化异步代码逻辑,减少阻塞。
  3. 后端层面
    • 使用LIMIT限制单次返回的数据量,
      SELECT id, name FROM cities WHERE province_id = ? LIMIT 1
0