Demo来源:http://www.imuum.com/plugin-jquery-cityselect-js-provinces-linkage-effect.html
我把Demo改写成最多可以到5级联动,需要增加修改也很容易
数据来源,Java端通过Spring boot输出将实体类转成JSON对象,转换效率有点低
TreeItem.java
public class TreeItem {
private String id;
private String pId;
private String name;
private String extra;
public TreeItem(String id,String pId,String name) {
this.id = id;
this.pId = pId;
this.name = name;
}
public TreeItem(String id,String pId, String name, String extra) {
this.id = id;
this.pId = pId;
this.name = name;
this.extra = extra;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getpId() {
return pId;
}
public void setpId(String pId) {
this.pId = pId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Tree.java
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Tree {
private List<TreeItem> nodes;
public Tree(List<TreeItem> nodes){
this.nodes = nodes;
}
public Map buildTree(){
List<Map<String,Object>> list=new ArrayList<>();
for (TreeItem node : nodes) {
String id = node.getId();
if (node.getpId() == null) {
list.add(build(node));
}
}
Map treeMap=new HashMap<>();
treeMap.put("citylist",list);
return treeMap;
}
private Map build(TreeItem node){
List<TreeItem> children = getChildren(node);
List<Map<String,Object>> list=new ArrayList<>();
Map<String,Object> map=new HashMap<>();
map.put("node",node);
if (children.isEmpty()) {
return map;
}
for (TreeItem child : children) {
list.add(build(child));
}
map.put("children",list);
return map;
}
private List<TreeItem> getChildren(TreeItem node){
List<TreeItem> children = new ArrayList<TreeItem>();
String id = node.getId();
for (TreeItem child : nodes) {
if (id.equals(child.getpId())) {
children.add(child);
}
}
return children;
}
}
通过调用Tree.buildTree函数就可以生成我们需要的json数据
然后就是前端页面了,预设值部分还没有做
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>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>基于jQuery+JSON的省市联动效果</title>
<script type="text/javascript" src="js/jquery.2.1.1.min.js"></script>
<script type="text/javascript" src="js/jquery.cityselect2.js"></script>
<script type="text/javascript">
$(function(){
$("#city").citySelect({
nodata:null,
required:false
});
});
</script>
</head>
<body>
<div id="main">
<div class="demo">
<h3>设置省份、城市、地区(县)的默认值</h3>
<p>三级联动</p>
<div id="city">
<select class="s0"></select>
<select class="s1" disabled="disabled"></select>
<select class="s2" disabled="disabled"></select>
<select class="s3" disabled="disabled"></select>
<select class="s4" disabled="disabled"></select>
</div>
</div>
</div>
<br />
<br />
</div>
</body>
</html>
cityselect2.js
/*
Ajax 多级联动
http://code.ciaoca.cn/
日期:2012-7-18
settings 参数说明
-----
url:省市数据josn文件路径
prov:默认省份
city:默认城市
dist:默认地区(县)
nodata:无数据状态
required:必选项
------------------------------ */
(function($){
$.fn.citySelect=function(settings){
if(this.length<1){return;};
// 默认值
settings=$.extend({
url:"js/city.js",
prov:null,
city:null,
dist:null,
nodata:null,
required:true
},settings);
var box_obj=this;
var s0_obj=box_obj.find(".s0");
var s1_obj=box_obj.find(".s1");
var s2_obj=box_obj.find(".s2");
var s3_obj=box_obj.find(".s3");
var s4_obj=box_obj.find(".s4");
var prov_val=settings.prov;
var select_prehtml=(settings.required) ? "" : "<option value=''>请选择</option>";
var city_json;
//获取当前选择框前面的选择框
var getPreS=function(s){
if(s==s1_obj) return s0_obj;
if(s==s2_obj) return s1_obj;
if(s==s3_obj) return s2_obj;
if(s==s4_obj) return s3_obj;
return null;
}
//获取当前选择框的下一个选择框
var getNextS=function(s){
if(s==s0_obj) return s1_obj;
if(s==s1_obj) return s2_obj;
if(s==s2_obj) return s3_obj;
if(s==s3_obj) return s4_obj;
return null;
}
//获取当前选择框的序号
var getSelectN=function(s){
if(s==s0_obj) return 0;
if(s==s1_obj) return 1;
if(s==s2_obj) return 2;
if(s==s3_obj) return 3;
return 4;
}
//根据当前选择框的值获取json数据的children
var getCityChildren=function(s){
var s0_id=s0_obj.get(0).selectedIndex;
var s1_id=s1_obj.get(0).selectedIndex;
var s2_id=s2_obj.get(0).selectedIndex;
var s3_id=s3_obj.get(0).selectedIndex;
var s4_id=s4_obj.get(0).selectedIndex;
if(!settings.required){
s0_id--;
s1_id--;
s2_id--;
s3_id--;
s4_id--;
};
if(s==s0_obj) return city_json.citylist[s0_id].children;
if(s==s1_obj) return city_json.citylist[s0_id].children[s1_id].children;
if(s==s2_obj) return city_json.citylist[s0_id].children[s1_id].children[s2_id].children;
if(s==s3_obj) return city_json.citylist[s0_id].children[s1_id].children[s2_id].children[s3_id].children;
return null;
}
//根据序号隐藏选择框
var hidSubSelect=function(n){
if(n<1){
s1_obj.empty().attr("disabled",false);
if(settings.nodata=="none"){
s1_obj.css("display","none");
}else if(settings.nodata=="hidden"){
s1_obj.css("visibility","hidden");
};
}
if(n<2){
s2_obj.empty().attr("disabled",false);
if(settings.nodata=="none"){
s2_obj.css("display","none");
}else if(settings.nodata=="hidden"){
s2_obj.css("visibility","hidden");
};
}
if(n<3){
s3_obj.empty().attr("disabled",false);
if(settings.nodata=="none"){
s3_obj.css("display","none");
}else if(settings.nodata=="hidden"){
s3_obj.css("visibility","hidden");
};
}
if(n<4){
s4_obj.empty().attr("disabled",false);
if(settings.nodata=="none"){
s4_obj.css("display","none");
}else if(settings.nodata=="hidden"){
s4_obj.css("visibility","hidden");
};
}
}
// 赋值地区(县)函数
var distStart=function(s){
var current_id=s.selectedIndex;
if(!settings.required){
current_id--;
};
hidSubSelect(getSelectN(s));
if(current_id<0||typeof(getCityChildren(s))=="undefined"||getCityChildren(s)==null){
if(settings.nodata=="none"){
getNextS(s).css("display","none");
}else if(settings.nodata=="hidden"){
getNextS(s).css("visibility","hidden");
};
return;
};
// 遍历
temp_html=select_prehtml;
$.each(getCityChildren(s),function(i,dist){
temp_html+="<option value='"+dist.node.id+"'>"+dist.node.name+"</option>";
});
getNextS(s).html(temp_html).attr("disabled",false).css({"display":"","visibility":""});
};
var init=function(){
// 遍历赋值省份下拉列表
temp_html=select_prehtml;
$.each(city_json.citylist,function(i,prov){
temp_html+="<option value='"+prov.node.id+"'>"+prov.node.name+"</option>";
});
s0_obj.html(temp_html);
// 若有传入省份与市级的值,则选中。(setTimeout为兼容IE6而设置)
setTimeout(function(){
if(settings.prov!=null){
prov_obj.val(settings.prov);
cityStart();
setTimeout(function(){
if(settings.city!=null){
city_obj.val(settings.city);
distStart();
setTimeout(function(){
if(settings.dist!=null){
dist_obj.val(settings.dist);
};
},1);
};
},1);
};
},1);
// 选择省份时发生事件
s0_obj.bind("change",function(){
distStart(s0_obj);
});
s1_obj.bind("change",function(){
distStart(s1_obj);
});
s2_obj.bind("change",function(){
distStart(s2_obj);
});
s3_obj.bind("change",function(){
distStart(s3_obj);
});
s4_obj.bind("change",function(){
distStart(s4_obj);
});
};
// 设置省市json数据
if(typeof(settings.url)=="string"){
$.getJSON(settings.url,function(json){
city_json=json;
init();
});
}else{
city_json=settings.url;
init();
};
};
})(jQuery);
把树的建立放到了前端js来建立
后端直接输出List<TreeItem>对象,框架自动输出JSON数组,前端js递归建树的代码如下
var districts;
var arrayToTree=function(parentId) {
var temp = [];
for (var index in districts) {
if (districts[index].pId == parentId) {
var children=arrayToTree(districts[index].id);
temp.push({
node: districts[index],
children: children
});
}
}
return temp;
};
var buildTree= function (parentId) {
var temp = {citylist:[]};
for (var index in districts) {
if (districts[index].id == parentId) {
temp.citylist.push({
node: districts[index],
children: arrayToTree(districts[index].id)
});
}
}
return temp;
};
在得到数据的时候修改一下
$.getJSON(settings.url, function (json) {
districts=json;
city_json = buildTree('000');//000是根节点的ID
init();
}
jquery.cityselect.js最后的Javascript代码如下
/*
多级联动 刘放
日期:2016-8-22
settings 参数说明
-----
url:省市数据josn文件路径
s0:默认省份
s1:默认市
s2:默认县
s3:默认乡镇
s4:默认村
nodata:无数据状态 如果需要隐藏则填写none或者hidden
required:必选项
依赖于web-storage-cache.min.js
------------------------------ */
(function($){
$.fn.citySelect=function(settings){
if(this.length<1){return;};
var wsCache = new WebStorageCache();
// 默认值
settings=$.extend({
url:null,
s1:null,
s2:null,
s3:null,
s4:null,
s0:null,
nodata:null,
required:true
},settings);
var box_obj=this;
var s0_obj=box_obj.find(".s0");
var s1_obj=box_obj.find(".s1");
var s2_obj=box_obj.find(".s2");
var s3_obj=box_obj.find(".s3");
var s4_obj=box_obj.find(".s4");
var text_obj=box_obj.find("input[type=hidden]");
var setTextObj=function(){
if(text_obj.length>0) {
if(s4_obj.val()!=="") {
text_obj.val(
s0_obj.find("option:selected").text()+
s1_obj.find("option:selected").text()+
s2_obj.find("option:selected").text()+
s3_obj.find("option:selected").text()+
s4_obj.find("option:selected").text());
}else{
text_obj.val("");
}
}
};
var prov_val=settings.prov;
var select_prehtml=(settings.required) ? "" : "<option value=''>请选择</option>";
var city_json;
//获取当前选择框前面的选择框
var getPreS=function(s){
if(s==s1_obj) return s0_obj;
if(s==s2_obj) return s1_obj;
if(s==s3_obj) return s2_obj;
if(s==s4_obj) return s3_obj;
return null;
}
//获取当前选择框的下一个选择框
var getNextS=function(s){
if(s==s0_obj) return s1_obj;
if(s==s1_obj) return s2_obj;
if(s==s2_obj) return s3_obj;
if(s==s3_obj) return s4_obj;
return null;
}
//获取当前选择框的序号
var getSelectN=function(s){
if(s==s0_obj) return 0;
if(s==s1_obj) return 1;
if(s==s2_obj) return 2;
if(s==s3_obj) return 3;
return 4;
}
//根据当前选择框的值获取json数据的children
var getCityChildren=function(s){
var s0_id=s0_obj.get(0).selectedIndex;
var s1_id=s1_obj.get(0).selectedIndex;
var s2_id=s2_obj.get(0).selectedIndex;
var s3_id=s3_obj.get(0).selectedIndex;
var s4_id=s4_obj.get(0).selectedIndex;
if(!settings.required){
s0_id--;
s1_id--;
s2_id--;
s3_id--;
s4_id--;
};
if(s===s0_obj) return city_json.list[s0_id].children;
if(s===s1_obj) return city_json.list[s0_id].children[s1_id].children;
if(s===s2_obj) return city_json.list[s0_id].children[s1_id].children[s2_id].children;
if(s===s3_obj) return city_json.list[s0_id].children[s1_id].children[s2_id].children[s3_id].children;
return null;
}
//根据序号隐藏选择框
var hidSubSelect=function(n){
if(n<1){
s1_obj.empty().attr("disabled",false);
if(settings.nodata=="none"){
s1_obj.css("display","none");
}else if(settings.nodata=="hidden"){
s1_obj.css("visibility","hidden");
};
}
if(n<2){
s2_obj.empty().attr("disabled",false);
if(settings.nodata=="none"){
s2_obj.css("display","none");
}else if(settings.nodata=="hidden"){
s2_obj.css("visibility","hidden");
};
}
if(n<3){
s3_obj.empty().attr("disabled",false);
if(settings.nodata=="none"){
s3_obj.css("display","none");
}else if(settings.nodata=="hidden"){
s3_obj.css("visibility","hidden");
};
}
if(n<4){
s4_obj.empty().attr("disabled",false);
if(settings.nodata=="none"){
s4_obj.css("display","none");
}else if(settings.nodata=="hidden"){
s4_obj.css("visibility","hidden");
};
}
}
// 赋值地区(县)函数
var distStart=function(s){
if($(s).val()==="") return;
var current_id=s.selectedIndex;
if(!settings.required){
current_id--;
};
hidSubSelect(getSelectN(s));
if(current_id<0||typeof(getCityChildren(s))=="undefined"||getCityChildren(s)==null){
if(settings.nodata=="none"){
getNextS(s).css("display","none");
}else if(settings.nodata=="hidden"){
getNextS(s).css("visibility","hidden");
};
return;
};
var next_obj=getNextS(s);//获取到下一个组件
if(next_obj==null) return;
// 遍历
temp_html=select_prehtml;
$.each(getCityChildren(s),function(i,dist){
temp_html+="<option value='"+dist.node.id+"'>"+dist.node.name+"</option>";
});
next_obj.html(temp_html).attr("disabled",false).css({"display":"","visibility":""});
if($(s).val()!==""){
distStart(next_obj);
}
};
var initCity=function(){
// 遍历赋值省份下拉列表
temp_html=select_prehtml;
$.each(city_json.list,function(i,prov){
temp_html+="<option value='"+prov.node.id+"'>"+prov.node.name+"</option>";
});
s0_obj.html(temp_html);
distStart(s0_obj);
// 若有传入省份与市级的值,则选中。(setTimeout为兼容IE6而设置)
setTimeout(function(){
if(settings.s0!==null&&settings.s0!==""){
s0_obj.val(settings.s0);
distStart(s0_obj);
setTimeout(function(){
if(settings.s1!=null){
if(s1_obj==null) return;
s1_obj.val(settings.s1);
distStart(s1_obj);
setTimeout(function(){
if(s2_obj==null) return;
if(settings.s2!=null){
s2_obj.val(settings.s2);
distStart(s2_obj);
setTimeout(function(){
if(s3_obj==null) return;
if(settings.s3!=null){
s3_obj.val(settings.s3);
distStart(s3_obj);
setTimeout(function(){
if(s4_obj==null) return;
if(settings.s4!=null){
s4_obj.val(settings.s4);
};
},1);
};
},1);
};
},1);
};
},1);
};
},1);
setTimeout(function(){
// 选择省份时发生事件
s0_obj.bind("change",function(){
distStart(s0_obj);
});
s1_obj.bind("change",function(){
distStart(s1_obj);
});
s2_obj.bind("change",function(){
distStart(s2_obj);
});
s3_obj.bind("change",function(){
distStart(s3_obj);
});
s4_obj.bind("change",function(){
distStart(s4_obj);
setTextObj();
});
},50);
};
var districts;
var arrayToTree=function(parentId) {
var temp = [];
for (var index in districts) {
if (districts[index].pId == parentId) {
var children=arrayToTree(districts[index].id);
temp.push({
node: districts[index],
children: children
});
}
}
return temp;
};
var buildTree= function (parentId) {
var temp = {list:[]};
for (var index in districts) {
if (districts[index].id == parentId) {
temp.list.push({
node: districts[index],
children: arrayToTree(districts[index].id)
});
}
}
return temp;
};
// 设置省市json数据
if(typeof(settings.url)=="string"){
city_json=wsCache.get("allCity");
if(city_json!==undefined&&city_json!==null){
initCity();
}
else {
$.getJSON(settings.url, function (json) {
districts=json;
city_json = buildTree('320000000000');//前端建好树
wsCache.set('allCity', city_json, {exp : 60*12});//缓存12*60s
initCity();
});
}
}else{
city_json=settings.url;
initCity();
};
};
})(jQuery);