灵活性方面考虑了比较多的方面,提供了几个重要的配置方便在各类环境下使用,欢迎各位童鞋使用,源码完全开放。开发这个插件的缘于前段时间维护一个4级级联下拉框被里面200行代码及复杂的结构和bug所郁闷(之所以这么多代码是因为该级联下拉框有时只出现2个或3个),想到这类的需求其实经常都能遇到,jquery里没有这样比较好的插件,索性自己开发个。源代码并不复杂,稍微复杂的地方在第二个插件使用了缓存,造成理解起来十分困难,后面会做些解释。
插件一:适合在不与服务器进行AJAX交互情况使用,需预先将所有下拉框数据全部读出
插件二:适用于每个子级下拉框都post到服务器中取数据绑定。优秀之处在于会将已使用过的数据缓存达到高效率的目的,注意:缓存的键值不仅仅是父下拉框的值,而是从顶级下拉框到当前父下拉框的值组合,这是为了对付出现相同父下拉框对应的子级并不相同的情况。同样的原因,postback中回发给服务器的form表单中也是包括所有的父下拉框的值。
复制代码 代码如下:
/*
* 级联下拉框Jqueyr插件,V1.2
* Copyright 2011, Leo.Liu
* 本插件包括2个无刷新级联下拉框插件:
* 插件一:cascadeDropDownData是在不与服务器进行AJAX交互情况使用,需预先将所有下拉框数据全部读出。demo:
* 方法一:var dataItem = [["全部", "-1", "0"], ["a001", "a001", "0"], ["a002", "a002", "0"], ["a003", "a003", "0"]
, ["b001", "b001", "a001"], ["b002", "b002", "a001"], ["b003", "b003", "a002"], ["b004", "b004", "a003"]
, ["c001", "001", "b001"], ["c002", "002", "b001"], ["c003", "003", "b002"], ["c004", "004", "b003"]];
$.cascadeDropDownBind.bind(dataItem, { sourceID: "Select1", selectValue: "a001", parentValue : "0",
child: { sourceID: "Select2", selectValue: "b002",
child: { sourceID: "Select3", selectValue: "c002"}
}
});
* 此方法有缺陷:a)要求下拉框的值与父子对应中的父值不能相同 b)不能设置全选规则
*
* 方法二:var data = [["全部", "0"], ["a001", "a001"], ["a002", "a002"], ["a003", "a003"]];
var data2 = [["全部", "0", "0"], ["b001", "b001", "a001"], ["b002", "b002", "a001"], ["b003", "b003", "a002"], ["b004", "b004", "a003"]];
var data3 = [["全部", "0", "0"], ["c001", "001", "b001"], ["c002", "002", "b001"], ["c003", "003", "b002"], ["c004", "004", "b003"]];
$.cascadeDropDownBind.bind(data, { sourceID: "Select1", selectValue: "a001" });
$.cascadeDropDownBind.bind(data2, { sourceID: "Select2", selectValue: "b002", parentID: "Select1" });
$.cascadeDropDownBind.bind(data3, { sourceID: "Select3", selectValue: "c002", parentID: "Select2" });
* 方法三参见cascadeDropDownBind.bind内容
*/
jQuery.extend({
//下拉框的数据对象
cascadeDropDownData: function () {
//******配置属性*******
this.removeFirst = true; //是否移除第一个项
this.appentAllValue = ""; //如果父项目的值等于此值则显示所有项
this.sourceID = ""; //此下拉框ID
this.parentID = ""; //父下拉框ID
this.items = []; //项的数据,二维数组,形式:[["文本", "值", "父ID"],......]; 值和父ID可省略
this.selectValue = ""; //初始化选中的项
this.parentValue = null; //用于从一堆数据中筛选出该组所需的项,一般用于绑定第一个下拉框
//******配置属性*******
//以下是全局变量,无需在外部设置
this.child = null;
var currentDrop = null;
this.bind = function () {
currentDrop = $("#" + this.sourceID);
this.clear();
//填充数据项目
this.fillItem();
//设置选中项
if (this.selectValue) {
currentDrop.val(this.selectValue);
}
//设置父下拉框的change事件
this.setChange();
};
//清理填充项目
this.clear = function () {
if (this.removeFirst) {
currentDrop.empty();
} else {
for (var i = currentDrop[0].options.length - 1; i > 0; i--) {
currentDrop[0].options[i] = null;
}
}
};
//填充数据项目
this.fillItem = function () {
var _parentValue = this.parentValue;
if (this.parentID)
_parentValue = $("#" + this.parentID).val();
var all = false;
if (this.appentAllValue && _parentValue == this.appentAllValue)
all = true;
$.each(this.items, function (index, item) {
var val = item.length > 1 ? item[1] : item[0]; //如果没有指定value则用text代替
if (all || item.length <= 2 || item[2] == _parentValue) { //如果长度小于3,认为没有父下拉框则填充所有项
currentDrop.append("<option value="" + val + "">" + item[0] + "</option>");
}
});
};
//设置父下拉框的change事件
this.setChange = function () {
if (this.parentID) {
$("#" + this.parentID).bind("change", this.change);
}
};
//父下拉框事件回调函数
var _this = this;
this.change = function () {
_this.clear();
_this.fillItem();
currentDrop.change();
};
},
cascadeDropDownBind: {
bind: function (data, setting) {
var obj = new $.cascadeDropDownData();
$.extend(obj, setting);
obj.items = data;
obj.bind();
if (setting.child) {
setting.child.parentID = setting.sourceID
this.bind(data, setting.child);
}
}
}
});
/*
* 插件二:ajaxDropDownData适用于每个子级下拉框都post到服务器中取数据绑定。
* 该插件优秀之处在于会将已使用过的数据缓存达到高效率的目的。
* 注意:缓存的键值不仅仅是父下拉框的值,而是从顶级下拉框到当前父下拉框的值组合,这是为了对付出现相同父下拉框对应的子级并不相同的情况
* 同样的原因,postback中回发给服务器的form表单中也是包括所有的父下拉框的值
* 使用方法:
var firstItems = null; //也可以将第一个下拉框的数据数组放到这进行绑定,或者设置为空,不改变下拉框。
$.ajaxDropDownBind.bindTopDrop("Select1", firstItems, null, false, "Select2");
$.ajaxDropDownBind.bindCallback("Select2", null, false, "Select3", "http://localhost:4167/GetDropDownData.ashx?action=select1");
$.ajaxDropDownBind.bindCallback("Select3", null, false, null, "http://localhost:4167/GetDropDownData.ashx?action=select2");
$("#Select1").change();
* 最重要的是级联的ID设置不能缺少。高级用法参见$.ajaxDropDownBind.bindCallback方法的内容。
*/
jQuery.extend({
//此对象是个链表结构
ajaxDropDownData: function () {
//******配置属性*******
this.sourceID = ""; //此下拉框ID
this.items = []; //此项的数据,二维数组,形式:[["文本", "值", "父ID"],......]; 值和父ID可省略
this.callback = null; //回调函数,用于获取下一级的方法,此函数接收2个参数:value, dropdownlist分别代表父级下拉框选中的值及本身的实例
this.childID = ""; //关联的子控件ID
this.removeFirst = true; //是否移除该项第一个选项
this.selectValue = ""; //此项初始化选中的值
//******配置属性*******
//********************下面是系统变量及方法****************************************************
this.childItem = []; //子对象列表,用于缓存
this.parentObj = null; //父对象
this.canChange = true;
this.clearItem = true;
this.bind = function () {
$.ajaxDropDownBind.bindData(this);
};
this.bindData = function (setting) {
$.extend(this, setting);
$.ajaxDropDownBind.bindData(this);
};
/*回溯到根节点,从根节点开始按照级联取当前正确的下拉框的对象
由于下拉框的事件只有一个,而对应的对象有多个,所以这里需要先回溯到根,在从根开始找起
*/
this.getRightOnChangeObj = function () {
if (this.parentObj)
return this.parentObj.getRightOnChangeObj().childItem[$("#" + this.parentObj.sourceID).val()]; //递归
else
return this;
}
},
ajaxDropDownBind: {
currentDrop: null,
_thisData: null,
callbackPool: [],
//清理填充项目
clear: function () {
if (_thisData.removeFirst) {
currentDrop.empty();
} else {
for (var i = currentDrop[0].options.length - 1; i > 0; i--) {
currentDrop[0].options[i] = null;
}
}
},
//填充数据项目
fillItem: function () {
for (var i = 0; i < _thisData.items.length; i++) {
var val = _thisData.items[i].length > 1 ? _thisData.items[i][1] : _thisData.items[i][0]; //如果没有指定value则用text代替
currentDrop.append("<option value="" + val + "">" + _thisData.items[i][0] + "</option>");
}
//设置选中项
if (_thisData.selectValue) {
currentDrop.val(_thisData.selectValue);
_thisData.selectValue = "";
}
},
//参数data是指当前变化的下拉框所在的对象
bindData: function (data) {
_thisData = data;
currentDrop = $("#" + _thisData.sourceID); //本身的节点而不是子级
if (_thisData.clearItem)
this.clear();
if (_thisData.items)
this.fillItem();
if (_thisData.childID) {
if (!currentDrop.data("binded")) { //判断是否绑定过事件,绑定过的不在绑定
currentDrop.data("binded", true);
var _firstChangeObj = _thisData; //由于下拉框的事件只有一个,而对应的对象有多个,所以这里的对象是绑定时的对象,而非正确的对象
currentDrop.bind("change", function () {
var rightChildItem = _firstChangeObj.getRightOnChangeObj().childItem;
var thisValue = $("#" + _firstChangeObj.sourceID).val(); //获取当前变化的下拉框的值,注意不能用currentDrop代替,因为currentDrop也是旧的值
if (rightChildItem[thisValue]) {
console.log("cache");
rightChildItem[thisValue].bind(); //使用缓存的数据来绑定
}
else {
console.log("getdata");
//一个新的实例,并建立链表关系
var dropData = new $.ajaxDropDownData();
dropData.sourceID = _firstChangeObj.childID;
dropData.parentObj = _firstChangeObj;
rightChildItem[thisValue] = dropData; //设置缓存
if (_firstChangeObj.callback) //如果有回调函数则直接调用,否则调用系统自动生成的函数
_firstChangeObj.callback(thisValue, dropData); //回调函数
else {
var callback = $.ajaxDropDownBind.callbackPool[dropData.sourceID];
if (callback)
callback(thisValue, dropData);
}
}
});
}
if (_thisData.canChange)
currentDrop.change();
}
},
//绑定第一级下拉框
bindTopDrop: function (sourceID, items, selectValue, removeFirst, childID) {
var mydrop = new $.ajaxDropDownData();
mydrop.sourceID = sourceID;
mydrop.items = items;
if (!items || items.length == 0)
mydrop.clearItem = false;
mydrop.removeFirst = removeFirst;
mydrop.selectValue = selectValue;
mydrop.childID = childID;
mydrop.canChange = false;
mydrop.bind();
},
//绑定子级下拉框
bindCallback: function (sourceID, selectValue, removeFirst, childID, parentPostUrl) {
var callback = function (value, dropdownlist) {
var postData = {};
var parentObj = dropdownlist.parentObj;
while (parentObj) {
postData[parentObj.sourceID] = $("#" + parentObj.sourceID).val();
parentObj = parentObj.parentObj;
}
$.getJSON(parentPostUrl + "&jsoncallback=?", postData, function (data) {
dropdownlist.items = data;
dropdownlist.removeFirst = removeFirst;
dropdownlist.selectValue = selectValue;
dropdownlist.childID = childID;
dropdownlist.bind();
});
};
this.callbackPool[sourceID] = callback;
}
}
});
使用方法代码里有注释,不赘述,欢迎拍砖。
不知道怎么添加附件,把测试代码也一并贴上来,因为插件二需要服务器端的配合这里就不贴插件二的测试代码。
插件一测试代码
复制代码 代码如下:
<!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 runat="server">
<title>无限极级联下拉框的封装</title>
<script type="text/javascript" src="http://test.fe.ecp.mic.cn/content/scripts/base/jquery.js"></script>
<style>
select
{
margin-left: 10px;
}
body
{
font-size: 14px;
background-color: #CCCCCC;
}
td
{
border: 1px solid #FF6600;
padding: 5px;
text-align: left;
}
input
{
width: 80px;
}
input[type=checkbox]
{
width: 20px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>
无限极级联下拉框的封装</h1>
<div style="margin: 50px 0 50px 10px;">
绑定方法:<select id="selCase"><option value="1">第一种方法</option>
<option value="2">第二种方法</option>
</select>
<input type="button" onclick="test()" value="绑定" />
<div style="margin: 10px;">
<table cellpadding="0" cellspacing="0">
<tr>
<td>
第一个下拉框:
</td>
<td>
<input type="text" id="tb1sel" value="a002" />设置当前项的选中值
</td>
<td>
</td>
<td>
</td>
</tr>
<tr>
<td>
第二个下拉框:
</td>
<td>
<input type="text" id="tb2sel" value="" />设置当前项的选中值
</td>
<td>
<input type="checkbox" id="cb2Remove" value="" />是否移除第一项
</td>
<td>
<input type="text" id="tb2AllValue" value="0" />当前一项值等于此值时,该项全选
</td>
</tr>
<tr>
<td>
第三个下拉框:
</td>
<td>
<input type="text" id="tb3sel" value="" />设置当前项的选中值
</td>
<td>
<input type="checkbox" id="cb3Remove" />是否移除第一项
</td>
<td>
<input type="text" id="tb3AllValue" value="" />当前一项值等于此值时,该项全选
</td>
</tr>
</table>
</div>
</div>
<h4>
下拉框结果:</h4>
<div id="selContainer" style="margin: 0px 0 50px 100px;">
</div>
<script type="text/javascript" src="/Scripts/Jquery.cascadeDropDown-1.2.js"></script>
<script type="text/javascript">
$(function () {
toggleSetting();
$("#selCase").bind("change", toggleSetting);
});
function toggleSetting() {
if ($("#selCase").val() == "1")
$("table tr").each(function (i, item) {
$($(item).find("td")[3]).hide();
});
else
$("table tr").each(function (i, item) {
$($(item).find("td")[3]).show();
});
}
function test() {
if ($("#selCase").val() == "1")
testcase1();
else
testcase2();
}
function testcase1() {
$("#Select1").remove();
$("#Select2").remove();
$("#Select3").remove();
$("#selContainer").html("<select id="Select1"><option value="-1">全部</option></select><select id="Select2"><option value="-1">全部</option></select><select id="Select3"><option value="-1">全部</option></select>");
var dataItem = [["a001", "a001", "0"], ["a002", "a002", "0"], ["a003", "a003", "0"]
, ["b001", "b001", "a001"], ["b002", "b002", "a001"], ["b003", "b003", "a002"], ["b004", "b004", "a002"], ["b005", "b005", "a003"]
, ["c001", "001", "b001"], ["c002", "002", "b001"], ["c003", "003", "b002"], ["c004", "004", "b002"], ["c005", "005", "b003"], ["c006", "006", "b004"], ["c007", "007", "b004"], ["c008", "008", "b005"]
];
$.cascadeDropDownBind.bind(dataItem,
{ sourceID: "Select1", selectValue: $("#tb1sel").val(), parentValue: "0", removeFirst: false,
child: { sourceID: "Select2", selectValue: $("#tb2sel").val(), removeFirst: $("#cb2Remove").attr("checked"),
child: { sourceID: "Select3", selectValue: $("#tb3sel").val(), removeFirst: $("#cb3Remove").attr("checked") }
}
}
);
}
function testcase2() {
$("#Select1").remove();
$("#Select2").remove();
$("#Select3").remove();
//$("#selContainer").html("<select id="Select1"></select><select id="Select2"></select><select id="Select3"></select>");
$("#selContainer").html("<select id="Select1"><option value="0">全部</option></select><select id="Select2"><option value="0">全部</option></select><select id="Select3"><option value="0">全部</option></select>");
var data = [["a001", "a001"], ["a002", "a002"], ["a003", "a003"]];
var data2 = [["b001", "b001", "a001"], ["b002", "b002", "a001"], ["b003", "b003", "a002"], ["b004", "b004", "a002"], ["b005", "b005", "a003"]];
var data3 = [["c001", "001", "b001"], ["c002", "002", "b001"], ["c003", "003", "b002"], ["c004", "004", "b002"], ["c005", "005", "b003"], ["c006", "006", "b004"], ["c007", "007", "b004"], ["c008", "008", "b005"]];
$.cascadeDropDownBind.bind(data, { sourceID: "Select1", selectValue: $("#tb1sel").val(), removeFirst: false });
$.cascadeDropDownBind.bind(data2, { sourceID: "Select2", selectValue: $("#tb2sel").val(), parentID: "Select1", removeFirst: $("#cb2Remove").attr("checked"), appentAllValue: $("#tb2AllValue").val() });
$.cascadeDropDownBind.bind(data3, { sourceID: "Select3", selectValue: $("#tb2sel").val(), parentID: "Select2", removeFirst: $("#cb3Remove").attr("checked"), appentAllValue: $("#tb3AllValue").val() });
}
</script>
</div>
</form>
</body>
</html>