省市县三级联动,在项目中应用的很广泛,也是很基础的功能。虽然说基础,其实其中还是包含一些小的问题,例如有一些新手做这个功能的时候,容易忽略:如果用户选择完省-市-县三级的时候,回头又重新选择了省,此时就应该讲市-县选择的内容清空。否则容易导致数据错误。
现在我就用 ThinkPHP5 来给 搭建大家展示这个简单的功能。为了演示的方便,我只在数据库中添加有效的地区数据,全国的数据,自己可自行百度。
~~~
DROP TABLE IF EXISTS `area`;
CREATE TABLE `area` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '地区id',
`name` varchar(155) NOT NULL COMMENT '地区名称',
`pid` int(11) NOT NULL COMMENT '上级地区id',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of area
-- ----------------------------
INSERT INTO `area` VALUES ('1', '江苏', '0');
INSERT INTO `area` VALUES ('2', '南京', '1');
INSERT INTO `area` VALUES ('3', '徐州', '1');
INSERT INTO `area` VALUES ('4', '苏州', '1');
INSERT INTO `area` VALUES ('5', '镇江', '1');
INSERT INTO `area` VALUES ('6', '江宁区', '2');
INSERT INTO `area` VALUES ('7', '浦口区', '2');
INSERT INTO `area` VALUES ('8', '建邺区', '2');
INSERT INTO `area` VALUES ('9', '玄武区', '2');
INSERT INTO `area` VALUES ('10', '云龙区', '3');
INSERT INTO `area` VALUES ('11', '泉山区', '3');
INSERT INTO `area` VALUES ('12', '鼓楼区', '3');
INSERT INTO `area` VALUES ('13', '铜山区', '3');
INSERT INTO `area` VALUES ('14', '姑苏区', '4');
INSERT INTO `area` VALUES ('15', '工业园区', '4');
INSERT INTO `area` VALUES ('16', '高新区', '4');
INSERT INTO `area` VALUES ('17', '京口区', '5');
INSERT INTO `area` VALUES ('18', '润州区', '5');
INSERT INTO `area` VALUES ('19', '镇江新区', '5');
INSERT INTO `area` VALUES ('20', '浙江', '0');
INSERT INTO `area` VALUES ('21', '杭州', '20');
INSERT INTO `area` VALUES ('22', '宁波', '20');
INSERT INTO `area` VALUES ('23', '上城区', '21');
INSERT INTO `area` VALUES ('24', '下城区', '21');
INSERT INTO `area` VALUES ('25', '西湖区', '21');
INSERT INTO `area` VALUES ('26', '江干区', '21');
INSERT INTO `area` VALUES ('27', '海曙区', '22');
INSERT INTO `area` VALUES ('28', '江东区', '22');
INSERT INTO `area` VALUES ('29', '江北区', '22');
~~~
数据库有了,那么我们来看看,控制器方面该如何设计,在Tools.php 中新建,一个 area:
~~~
// 三级联动
public function area()
{
if(request()->isAjax()){
$code = input('post.code');
$lists = db('area')->where('pid', $code)->select();
return json(['code' => 1, 'data' => $lists, 'msg' => 'ok']);
}
$province = db('area')->where('pid', 0)->select();
$this->assign([
'province' => $province
]);
return $this->fetch();
}
~~~
代码就是这么的简洁。默认查出省份渲染到前台,用户触发选择,就把用户选择 id 发送过来,后台查询他的 子类即可。看一下欠他页面和关键的 js 部分代码,在 application\\index\\view\\tools 下面 新建 area.html
~~~
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>省-市-县三级联动</title>
<link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="wrapper wrapper-content">
<h1>省-市-县三级联动</h1>
<div class="row col-sm-6">
<div class="col-sm-4">
<select class="form-control m-b" id="p">
<option value="0" data-id="0">不限区域</option>
{foreach name="province" item="vo"}
<option value="{$vo.name}" data-id="{$vo.id}">{$vo.name}</option>
{/foreach}
</select>
</div>
<div class="col-sm-4">
<select class="form-control m-b" id="c" disabled>
<option value="0" data-id="0">请选择城市</option>
</select>
</div>
<div class="col-sm-4">
<select class="form-control m-b" id="a" disabled>
<option value="0" data-id="0">请选择区</option>
</select>
</div>
</div>
</div>
<script src="/static/js/jquery.min.js?v=2.1.4"></script>
<script src="/static/bootstrap/js/bootstrap.min.js"></script>
<script>
var area_url = "{:url('tools/area')}";
$(function(){
//省市区,三级联动 ---- begin -----
$("#p").change(function(){
var pid = $(this).find("option:selected").attr('data-id');
//已经选择了省份,又不选择省份,改变属性
if( '0' == pid){
$("#pname").val('不限区域');
$("#c").html('<option value="0" data-id="0">选择城市</option>').attr('disabled', true);
$("#a").html('<option value="0" data-id="0">选择区</option>').attr('disabled', true);
}
if('0' == pid){
return ;
}
$.post(area_url, {'code' : pid}, function(res){
if(1 == res.code){
var _html = '<option value="0" data-id="0">选择城市</option>';
$.each(res.data, function(k, v){
_html += '<option value="' + v.name + '" data-id="' + v.id + '">' + v.name + '</option>';
});
$('#c').html(_html);
}
}, 'json');
$("#c").removeAttr('disabled'); //去除不可选状态
$("#a").html('<option value="0" data-id="0">选择区</option>').attr('disabled', true);
});
$("#c").change(function(){
var cid = $(this).find("option:selected").attr('data-id');
//已经选择了城市,又不选择城市,改变属性
if( '0' == cid){
$("#cname").val('');
$("#a").html('<option value="0" data-id="0">选择区</option>').attr('disabled', true);
}
if( '0' == cid ){
return ;
}
$.post(area_url, {'code' : cid}, function(res){
if(1 == res.code){
var _html = '<option value="0" data-id="0">选择区</option>';
$.each(res.data, function(k, v){
_html += '<option value="' + v.name + '" data-id="' + v.id + '">' + v.name + '</option>';
});
$('#a').html(_html);
}
}, 'json');
$("#a").removeAttr('disabled'); //去除不可选状态
});
$("#a").change(function(){
var aid = $(this).find("option:selected").attr('data-id');
if('0' == aid){
$("#aname").val('');
}
});
//---- end -----
});
</script>
</body>
</html>
~~~
效果如下:
![](https://box.kancloud.cn/7a17e8af3406f28aa140010ce14ceced_956x241.jpg)
![](https://box.kancloud.cn/de2197d57bdb004a1bdb4ea05909f7a2_949x209.jpg)