基于jquery的无限级联下拉框js插件 |
本文标签:无限级联,下拉框 灵活性方面考虑了比较多的方面,提供了几个重要的配置方便在各类环境下使用,欢迎各位童鞋使用,源码完全开放 。开发这个插件的缘于前段时间维护一个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> |