本文详细介绍如何利用PHP、MySQL、Ajax和JavaScript实现省市区三级联动功能。通过前端JS动态创建select控件,利用Ajax与后端PHP交互获取数据库中的行政区划数据,并根据用户选择动态更新下级菜单选项,实现流畅的无刷新交互体验。
三级联动核心原理
核心思路在于利用JavaScript动态生成select元素的option选项,并通过Ajax技术从PHP后端获取存储在SQL数据库中的省市区数据。虽然代码量较大,但逻辑结构相似,例如JS中获取省、市、区的方法类似,PHP端则根据传入参数的不同执行相应的SQL查询语句。
HTML页面结构
index.html页面代码结构如下:
具体实现代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>省市区三级联动</title>
<META http-equiv=Content-Type content="text/html; charset=gb2312">
<script src="scripts/thumbnails.js" type="text/javascript"></script>
</head>
<body>
<div id="description">
<select style="width:100px; " onchange="sech(this.id)" id="sheng">
<option value="province">请选择省份</option>
</select>
<select onchange="sech(this.id)" id="shi">
<option value="city">请选择市区</option>
</select>
<select id="xian">
<option value="county">请选择县乡</option>
</select>
</div>
</div>
</body>
</html>
JavaScript交互逻辑
thumbnails.js脚本代码实现如下:
具体JS代码内容:
window.onload = getProvince;
function createRequest() {//用于Ajax与PHP交互的请求对象创建
try {
request = new XMLHttpRequest();//创建标准的XMLHttpRequest对象;
} catch (tryMS) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (otherMS) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
request = null;
}
}
}
return request;
}
function sech(id) {//当省或市发生变化时触发,对应select的onchange事件
var aa = document.getElementById(id);
if(id=="sheng"){
getCity(aa.value);//此处aa.value代表所选省份的ID
}
if(id=="shi")
{
getCounty(aa.value);//此处aa.value代表所选城市的ID
}
}
function getProvince() {//用于获取所有省份数据
request = createRequest();
if (request == null) {
alert("Unable to create request");
return;
}
var url= "getDetails.php?ID=0";//当ID=0时,PHP端将返回所有省份数据
request.open("GET", url, true);
request.onreadystatechange = displayProvince; //设置回调处理函数
request.send(null); //发送HTTP请求
}
function getCity(id){//根据省份ID获取对应的城市列表
request = createRequest();
if (request == null) {
alert("Unable to create request");
return;
}
var url= "getDetails.php?ID=" + escape(id);
request.open("GET", url, true);
request.onreadystatechange = displayCity;
request.send(null);
}
function getCounty(id){//根据城市ID获取对应的区县列表
request = createRequest();
if (request == null) {
alert("Unable to create request");
return;
}
var url= "getDetails.php?ID=" + escape(id);
request.open("GET", url, true);
request.onreadystatechange = displayCounty;
request.send(null);
}
function displayProvince() {//将获取到的省份数据动态添加到select控件中
if (request.readyState == 4) {
if (request.status == 200) {
var a=new Array;
var b=request.responseText;//将PHP返回的响应文本赋值给变量b
a=b.split(",");//通过逗号分隔符将数据存入数组a
document.getElementById("sheng").length=1;
var obj=document.getElementById("sheng');
for(i=0;i
obj.options.add(new Option(a[i],i+1)); //动态生成OPTION并添加到select,第一个参数为显示文本,第二个参数为值。
}
}
}
function displayCity() {//将获取到的城市数据动态添加到select控件中
if (request.readyState == 4) {
if (request.status == 200) {
var a=new Array;
var b=request.responseText;
a=b.split(",");
document.getElementById("shi").length=1;//重置城市下拉框
document.getElementById("xian").length=1;//重置区县下拉框
if(document.getElementById("sheng").value!="province"){
var obj=document.getElementById('shi');
for(i=0;i
obj.options.add(new Option(a[i], document.getElementById("sheng").value*100+i+1)); //计算出的值对应城市的ID。
}
}
}
}
function displayCounty() {//将获取到的区县数据动态添加到select控件中
if (request.readyState == 4) {
if (request.status == 200) {
var a=new Array;
var b=request.responseText;
a=b.split(",");
document.getElementById("xian").length=1;
if(document.getElementById("sheng").value!="province"&&document.getElementById("shi").value!="city"){
var obj=document.getElementById('xian');
for(i=0;i
obj.options.add(new Option(a[i],i+1001));
}
}
}
}
PHP后端数据处理
getDetails.php后端处理代码:
PHP服务端具体实现如下:
<?php
header("Content-Type: text/html; charset=gb2312");
$conn = new COM("ADODB.Connection") or die("Cannot start ADO");
$connstr = "Provider=SQLOLEDB;Persist Security Info=False;User ID=root;Password=123456;Initial Catalog=area;Data Source=localhost";
if($_REQUEST['ID']==0){//当ID为0时,获取省份列表
$conn->Open($connstr); //建立数据库连接
$sqlstr = "select name from Province"; //定义查询语句
$rs = $conn->Execute($sqlstr); //执行查询获取结果集
$num_cols = $rs->Fields->Count(); //获取字段数量
$Province=array();
$i=0;
while (!$rs->EOF) {
$Province[$i]=$rs->Fields['name']->Value.",";
$rs->MoveNext();
$i++;
}
foreach($Province as $val)
echo $val;
$conn->Close();
$rs = null;
$conn = null;
}
if($_REQUEST['ID']>0&&$_REQUEST['ID']<35){//当ID在0到35之间时,获取对应省份的城市列表
$conn->Open($connstr); //建立数据库连接
$sqlstr = "select name from City where cid=".$_REQUEST['ID']; //定义查询语句
$rs = $conn->Execute($sqlstr); //执行查询获取结果集
$num_cols = $rs->Fields->Count(); //获取字段数量
$City=array();
$i=0;
while (!$rs->EOF) {
$City[$i]=$rs->Fields['name']->Value.",";
$rs->MoveNext();
$i++;
}
foreach($City as $val)
echo $val;
$conn->Close();
$rs = null;
$conn = null;
}
if($_REQUEST['ID']>100){//当ID大于100时,获取对应城市的区县列表
$conn->Open($connstr); //建立数据库连接
$sqlstr = "select name from County where cid=".$_REQUEST['ID']; //定义查询语句
$rs = $conn->Execute($sqlstr); //执行查询获取结果集
$num_cols = $rs->Fields->Count(); //获取字段数量
$County=array();
$i=0;
while (!$rs->EOF) {
$County[$i]=$rs->Fields['name']->Value.",";
$rs->MoveNext();
$i++;
}
foreach($County as $val)
echo $val;
$conn->Close();
$rs = null;
$conn = null;
}
?>
数据库表结构设计
数据库设计方面,需建立Province、City、County三张表。Province表包含id和name字段,建议id从1至34编号,如北京为1,广东为2;City表包含id、name和cid字段,id计算公式为cid*100+1,其中cid表示上级城市ID,例如深圳隶属于广东(cid为2),则深圳id为201;County表包含id、name和cid字段,id建议从10001开始自增,cid表示所属上级城市ID,如宝安区和龙岗区隶属于深圳(cid为201),则它们的cid均为201。
界面截图展示:
HTML页面初始效果:

最终运行效果展示:



注意事项:PHP代码运行在服务器端,建议在网站发布后通过IP地址进行调试测试。