基础
为了代码的简洁性,不再编写繁琐的类似document.getElementById(id)这样的语句(用jquery只需要这样写:$("#id"),显然更加方便),本文将使用jquery来编写js代码。因此本文适合有一定jquery基础的读者来阅读(只需要了解jquery的一些基础就行),不会jquery的读者也不必担心,可以去简单的学习下jquery即可。一个下拉列表就像下面这样:
<select name="name">
<option value="value1">text1</option>
<option value="value2">text2</option>
......
</select>
一个下拉列表就是由<select>标签以及其子标签<option>组成,一个<option>标签就是下拉列表的一个选项,默认只能选择一项,如果想要选择多项则需要设置<select>标签的属性multiple="multiple",size属性指定可以选择多少项,进行选择时按住CTRL键可以选择多项。可以通过设置option的属性selected="selected"来让该项被选中。注意:如果选择了多项,select元素 的value属性的值等于第一个被选中的option元素的value属性的值,如果想要获取所有被选择项的值,那么就需要遍历select元素下的所有option元素,再通过option的selected属性值来判断该项是否被选中。
在开发时常常需要类似省市这样的二级下拉列表联动(或者是多级联动),这些联动效果可能只是在项目开发过程中遇到时根据实际情况写的代码,并没有通用性,下次遇到时或者从网上copy代码或者从自己已经做过的项目中copy代码,然后修改下就完事了,我在开发过的所有项目中发现这样的代码还不少。我们并不想要一直反反复复的写这些代码,要是能做成一个插件,需要联动效果的时候直接拿过啦用该多好啊!
一个简单的省市下拉列表就是这样的(这里只是简略的列举了一些省市):
<select name="province">
<option value="420000">湖北省</option>
<option value="430000">湖南省</option>
<option value="440000">广东省</option>
</select>
<select name="city">
<option value="420100">武汉市</option>
<option value="420700">鄂州市</option>
<option value="420800">荆门市</option>
<option value="420900">孝感市</option>
</select>
我们想要的效果是:当选择某个省时,市下拉列表应该填充成该省下的所有市。接下来一步步来完成联动效果:
联动下拉列表
简单的二级省市联动
HTML:
<select name="province">
<option value="">请选择</option>
<option value="420000">湖北省</option>
<option value="430000">湖南省</option>
<option value="440000">广东省</option>
</select>
<select name="city">
<option value="">请选择</option>
</select>
JS:
$(function() {
var data = {
"420000": {
"420100": "武汉市",
"420700": "鄂州市",
"420800": "荆门市",
"420900": "孝感市"
},
"430000": {
"430100": "长沙市",
"430600": "岳阳市"
},
"440000": {
"440200": "韶关市",
"440400": "珠海市",
"440500": "汕头市",
"440600": "佛山市",
"440800": "湛江市"
}
};
//为province下拉列表绑定change事件
$("select[name='province']").bind("change", function() {
var $city = $("select[name='city']");
//删除city下拉列表的所有子元素
$city.empty();
var provinceCode = $(this).val();
var city = data[provinceCode];
var $cityOption = $("<option value=''>请选择</option>");
$city.append($cityOption);
if(!!provinceCode && !!city) {
for(var code in city) {
$cityOption = $("<option value=\""+code+"\">"+city[code]+"</option>");
$city.append($cityOption);
}
}
});
});
首先给省下拉选绑定onchange事件,当选择某一个省时,先清除所有的市下拉选,然后从data中获取所有的市,然后再填充到市下拉选,上面的市数据应该是从数据库里面查询出来,然后返回一个JSON字符串,我上面只是用一个变量写死到里面了。上面在添加市下拉选的过程中,先是创建一个<option>元素,然后再添加到市下拉选,这样性能其实很差,每次添加后浏览器都要渲染,上面的js需要优化,优化后的js如下:
$(function() {
var data = {
"420000": {
"420100": "武汉市",
"420700": "鄂州市",
"420800": "荆门市",
"420900": "孝感市"
},
"430000": {
"430100": "长沙市",
"430600": "岳阳市"
},
"440000": {
"440200": "韶关市",
"440400": "珠海市",
"440500": "汕头市",
"440600": "佛山市",
"440800": "湛江市"
}
};
//为province下拉列表绑定change事件
$("select[name='province']").bind("change", function() {
var $city = $("select[name='city']");
//删除city下拉列表的所有子元素
$city.empty();
var provinceCode = $(this).val();
var city = data[provinceCode];
var output = ["<option value=''>请选择</option>"];
if(!!provinceCode && !!city) {
for(var code in city) {
output.push("<option value=\""+code+"\">"+city[code]+"</option>");
}
}
$city.html(output.join(""));
});
});
上面优化的代码将HTML片段放入一个数组,然后调用数组的join()方法将数组连接成一个字符串,再调用html()方法添加所有的市下拉选。
简单省市县的三级联动
HTML
<select name="province">
<option value="">请选择</option>
<option value="420000">湖北省</option>
<option value="430000">湖南省</option>
</select>
<select name="city">
<option value="">请选择</option>
</select>
<select name="county">
<option value="">请选择</option>
</select>
JS
$(function() {
var cityData = {
"420000": {
"420100": "武汉市",
},
"430000": {
"430100": "长沙市",
"430600": "岳阳市"
}
};
var countyData = {
"420100": {
"420102": "江岸区",
"420103": "江汉区",
"420104": "硚口区",
"420105": "汉阳区 ",
"420106": "武昌区 "
},
"430100": {
"430102": "芙蓉区",
"430103": "天心区",
"430104": "岳麓区"
},
"430600": {
"430602": "岳阳楼区",
"430603": "云溪区",
"430611": "君山区",
"430621": "岳阳县"
}
};
//为province下拉列表绑定change事件
$("select[name='province']").bind("change", function() {
var $city = $("select[name='city']");
//删除city下拉列表的所有子元素
$city.empty();
var provinceCode = $(this).val();
var city = cityData[provinceCode];
var output = ["<option value=''>请选择</option>"];
if(!!provinceCode && !!city) {
for(var code in city) {
output.push("<option value=\""+code+"\">"+city[code]+"</option>");
}
}
$city.html(output.join(""));
});
//为city下拉选绑定change事件
$("select[name='city']").bind("change", function() {
var $county = $("select[name='county']");
$county.empty();
var cityCode = $(this).val();
var county = countyData[cityCode];
var output = ["<option value=''>请选择</option>"];
if(!!cityCode && !!county) {
for(var code in county) {
output.push("<option value=\""+code+"\">"+county[code]+"</option>");
}
}
$county.html(output.join(""));
});
});
三级下拉选级联其实和二级下拉选级联很类似,只不过是多加了一个change事件,当某个下拉选的值改变时,去获取下一个下拉选(最后一个下拉选不需要绑定事件)应该填充的数据,然后再填充数据。如果是多级级联依此类推就行了,一般情况下三级~四级级联就够用了。上面的代码有需要优化的地方,比如下拉选的填充可以抽取一个方法出来,但是处于篇幅的考虑,这里就不提取出来了,接下来的某个部分会贴出优化后的代码!
二级省市联动 - 从xml文件获取数据
province.xml
<?xml version="1.0" encoding="UTF-8"?>
<provinces>
<province name="湖北省" code="420000">
<city name="武汉市" code="420100"></city>
<city name="鄂州市" code="420700"></city>
<city name="荆门市" code="420800"></city>
<city name="孝感市" code="420900"></city>
</province>
<province name="湖南省" code="430000">
<city name="长沙市" code="430100"></city>
<city name="岳阳市" code="430600"></city>
</province>
<province name="广东省" code="440000">
<city name="韶关市" code="440200"></city>
<city name="珠海市" code="440400"></city>
<city name="汕头市" code="440500"></city>
<city name="湛江市" code="440800"></city>
</province>
</provinces>
JS
//加载xml文件
var xmlDoc = loadXMLDoc("province.xml");
var rootElement = xmlDoc.documentElement;
$(function() {
//为province下拉列表绑定change事件
$("select[name='province']").bind("change", function() {
var $city = $("select[name='city']");
//删除city下拉列表的所有子元素
$city.empty();
var provinceCode = $(this).val();
var output = ["<option value=''>请选择</option>"];
if(!!provinceCode) {
var xCityElement = findXmlChildNodesByCode(rootElement, provinceCode);
if(!!xCityElement) {
var xCityNodes = xCityElement.childNodes, len = xCityNodes.length;
for(var i = 0; i < len; i++) {
var xCityNode = xCityNodes[i];
//有些浏览器,例如火狐将文本节点也包含在内了
if(!xCityNode.tagName) {
continue;
}
var cityCode = xCityNode.attributes.getNamedItem("code").nodeValue;
var cityName = xCityNode.attributes.getNamedItem("name").nodeValue;
output.push("<option value=\""+cityCode+"\">"+cityName+"</option>");
}
}
}
$city.html(output.join(""));
});
});
function loadXMLDoc(dname) {
try {
//IE
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
} catch (e) {
//Firefox, Mozilla, Opera, etc.
try {
xmlDoc=document.implementation.createDocument("","",null);
} catch (e) {
alert(e.message);
}
}
try {
xmlDoc.async=false;
xmlDoc.load(dname);
return(xmlDoc);
} catch (e) {
alert(e.message);
}
return null;
}
function findXmlChildNodesByCode(parentElement, code) {
var childNodes = parentElement.childNodes, childNode,
i, len = childNodes.length;
for(i = 0; i < len; i++) {
childNode = childNodes[i];
//有些浏览器,例如火狐将文本节点也包含在内了
if(!childNode.tagName) {
continue;
}
var _code = childNode.attributes.getNamedItem("code").nodeValue;
if(_code == code) {
return childNode;
}
}
return null;
}
loadXMLDoc(dname)里面封装了加载xml文件的代码,通过此方法获取加载的xml对象,XML DOM提供了修改的方法和属性,具体的可以查看本文最后的学习资料。在省下拉选绑定的事件回调函数中,通过findXmlChildNodesByCode(parentEle, code)(这种遍历有点麻烦,其实可以用XPath表达式来获取指定的节点,这种方法效率更高)根据省代码来查询其下的所有市节点,然后遍历所有的市节点,获取代码和名称并填充到市下拉框。上面获取到的某个省的所有市数据可以缓存起来,以便以后再使用,以免每次都是去遍历XML查询指定时,提交效率。
总结
下拉框的联动重点在于给哪些下拉框绑定change事件,当改变某个下拉框的值时,其他某个或者是某些下拉框应该填充什么数据。本文只是硬编码的将这些数据写死到程序里了,实际的情况可能是从后台获取数据,然后解析后台返回的数据。下拉框的联动其实并不是很难,只是每次写这样的代码确实有点麻烦,我们当然希望越简单越方便就越好```
下载地址及参考资料