UDN-企业互联网技术人气社区

板块导航

浏览  : 586
回复  : 5

[jQuery] 基于jquery的无限级联下拉框js插件

[复制链接]
山外青山的头像 楼主
发表于 2016-12-13 16:10:18 | 显示全部楼层 |阅读模式
      首先声明这2个无刷新级联下拉框的jquery插件完全是自己原创的,经过严格的测试,正确使用不会出现bug

      灵活性方面考虑了比较多的方面,提供了几个重要的配置方便在各类环境下使用,欢迎各位童鞋使用,源码完全开放。开发这个插件的缘于前段时间维护一个4级级联下拉框被里面200行代码及复杂的结构和bug所郁闷(之所以这么多代码是因为该级联下拉框有时只出现2个或3个),想到这类的需求其实经常都能遇到,jquery里没有这样比较好的插件,索性自己开发个。源代码并不复杂,稍微复杂的地方在第二个插件使用了缓存,造成理解起来十分困难,后面会做些解释。

      插件一:适合在不与服务器进行AJAX交互情况使用,需预先将所有下拉框数据全部读出

      插件二:适用于每个子级下拉框都post到服务器中取数据绑定。优秀之处在于会将已使用过的数据缓存达到高效率的目的,注意:缓存的键值不仅仅是父下拉框的值,而是从顶级下拉框到当前父下拉框的值组合,这是为了对付出现相同父下拉框对应的子级并不相同的情况。同样的原因,postback中回发给服务器的form表单中也是包括所有的父下拉框的值。

      复制代码 代码如下:
  1. /*
  2. * 级联下拉框Jqueyr插件,V1.2
  3. * Copyright 2011, Leo.Liu
  4. * 本插件包括2个无刷新级联下拉框插件:
  5. * 插件一:cascadeDropDownData是在不与服务器进行AJAX交互情况使用,需预先将所有下拉框数据全部读出。demo:
  6. * 方法一:var dataItem = [['全部', '-1', '0'], ['a001', 'a001', '0'], ['a002', 'a002', '0'], ['a003', 'a003', '0']
  7. , ['b001', 'b001', 'a001'], ['b002', 'b002', 'a001'], ['b003', 'b003', 'a002'], ['b004', 'b004', 'a003']
  8. , ['c001', '001', 'b001'], ['c002', '002', 'b001'], ['c003', '003', 'b002'], ['c004', '004', 'b003']];
  9. $.cascadeDropDownBind.bind(dataItem, { sourceID: 'Select1', selectValue: 'a001', parentValue : '0',
  10. child: { sourceID: 'Select2', selectValue: 'b002',
  11. child: { sourceID: 'Select3', selectValue: 'c002'}
  12. }
  13. });
  14. * 此方法有缺陷:a)要求下拉框的值与父子对应中的父值不能相同 b)不能设置全选规则
  15. *
  16. * 方法二:var data = [['全部', '0'], ['a001', 'a001'], ['a002', 'a002'], ['a003', 'a003']];
  17. var data2 = [['全部', '0', '0'], ['b001', 'b001', 'a001'], ['b002', 'b002', 'a001'], ['b003', 'b003', 'a002'], ['b004', 'b004', 'a003']];
  18. var data3 = [['全部', '0', '0'], ['c001', '001', 'b001'], ['c002', '002', 'b001'], ['c003', '003', 'b002'], ['c004', '004', 'b003']];
  19. $.cascadeDropDownBind.bind(data, { sourceID: 'Select1', selectValue: 'a001' });
  20. $.cascadeDropDownBind.bind(data2, { sourceID: 'Select2', selectValue: 'b002', parentID: 'Select1' });
  21. $.cascadeDropDownBind.bind(data3, { sourceID: 'Select3', selectValue: 'c002', parentID: 'Select2' });
  22. * 方法三参见cascadeDropDownBind.bind内容
  23. */
  24. jQuery.extend({
  25. //下拉框的数据对象
  26. cascadeDropDownData: function () {
  27. //******配置属性*******
  28. this.removeFirst = true; //是否移除第一个项
  29. this.appentAllValue = ''; //如果父项目的值等于此值则显示所有项
  30. this.sourceID = ''; //此下拉框ID
  31. this.parentID = ''; //父下拉框ID
  32. this.items = []; //项的数据,二维数组,形式:[['文本', '值', '父ID'],......]; 值和父ID可省略
  33. this.selectValue = ''; //初始化选中的项
  34. this.parentValue = null; //用于从一堆数据中筛选出该组所需的项,一般用于绑定第一个下拉框
  35. //******配置属性*******
  36. //以下是全局变量,无需在外部设置
  37. this.child = null;
  38. var currentDrop = null;
  39. this.bind = function () {
  40. currentDrop = $('#' + this.sourceID);
  41. this.clear();
  42. //填充数据项目
  43. this.fillItem();
  44. //设置选中项
  45. if (this.selectValue) {
  46. currentDrop.val(this.selectValue);
  47. }
  48. //设置父下拉框的change事件
  49. this.setChange();
  50. };
  51. //清理填充项目
  52. this.clear = function () {
  53. if (this.removeFirst) {
  54. currentDrop.empty();
  55. } else {
  56. for (var i = currentDrop[0].options.length - 1; i > 0; i--) {
  57. currentDrop[0].options[i] = null;
  58. }
  59. }
  60. };
  61. //填充数据项目
  62. this.fillItem = function () {
  63. var _parentValue = this.parentValue;
  64. if (this.parentID)
  65. _parentValue = $('#' + this.parentID).val();
  66. var all = false;
  67. if (this.appentAllValue && _parentValue == this.appentAllValue)
  68. all = true;
  69. $.each(this.items, function (index, item) {
  70. var val = item.length > 1 ? item[1] : item[0]; //如果没有指定value则用text代替
  71. if (all || item.length <= 2 || item[2] == _parentValue) { //如果长度小于3,认为没有父下拉框则填充所有项
  72. currentDrop.append('<option value="' + val + '">' + item[0] + '</option>');
  73. }
  74. });
  75. };
  76. //设置父下拉框的change事件
  77. this.setChange = function () {
  78. if (this.parentID) {
  79. $('#' + this.parentID).bind('change', this.change);
  80. }
  81. };
  82. //父下拉框事件回调函数
  83. var _this = this;
  84. this.change = function () {
  85. _this.clear();
  86. _this.fillItem();
  87. currentDrop.change();
  88. };
  89. },
  90. cascadeDropDownBind: {
  91. bind: function (data, setting) {
  92. var obj = new $.cascadeDropDownData();
  93. $.extend(obj, setting);
  94. obj.items = data;
  95. obj.bind();
  96. if (setting.child) {
  97. setting.child.parentID = setting.sourceID
  98. this.bind(data, setting.child);
  99. }
  100. }
  101. }
  102. });
  103. /*
  104. * 插件二:ajaxDropDownData适用于每个子级下拉框都post到服务器中取数据绑定。
  105. * 该插件优秀之处在于会将已使用过的数据缓存达到高效率的目的。
  106. * 注意:缓存的键值不仅仅是父下拉框的值,而是从顶级下拉框到当前父下拉框的值组合,这是为了对付出现相同父下拉框对应的子级并不相同的情况
  107. * 同样的原因,postback中回发给服务器的form表单中也是包括所有的父下拉框的值
  108. * 使用方法:
  109. var firstItems = null; //也可以将第一个下拉框的数据数组放到这进行绑定,或者设置为空,不改变下拉框。
  110. $.ajaxDropDownBind.bindTopDrop('Select1', firstItems, null, false, 'Select2');
  111. $.ajaxDropDownBind.bindCallback('Select2', null, false, 'Select3', 'http://localhost:4167/GetDropDownData.ashx?action=select1');
  112. $.ajaxDropDownBind.bindCallback('Select3', null, false, null, 'http://localhost:4167/GetDropDownData.ashx?action=select2');
  113. $('#Select1').change();
  114. * 最重要的是级联的ID设置不能缺少。高级用法参见$.ajaxDropDownBind.bindCallback方法的内容。
  115. */
  116. jQuery.extend({
  117. //此对象是个链表结构
  118. ajaxDropDownData: function () {
  119. //******配置属性*******
  120. this.sourceID = ''; //此下拉框ID
  121. this.items = []; //此项的数据,二维数组,形式:[['文本', '值', '父ID'],......]; 值和父ID可省略
  122. this.callback = null; //回调函数,用于获取下一级的方法,此函数接收2个参数:value, dropdownlist分别代表父级下拉框选中的值及本身的实例
  123. this.childID = ''; //关联的子控件ID
  124. this.removeFirst = true; //是否移除该项第一个选项
  125. this.selectValue = ''; //此项初始化选中的值
  126. //******配置属性*******
  127. //********************下面是系统变量及方法****************************************************
  128. this.childItem = []; //子对象列表,用于缓存
  129. this.parentObj = null; //父对象
  130. this.canChange = true;
  131. this.clearItem = true;
  132. this.bind = function () {
  133. $.ajaxDropDownBind.bindData(this);
  134. };
  135. this.bindData = function (setting) {
  136. $.extend(this, setting);
  137. $.ajaxDropDownBind.bindData(this);
  138. };
  139. /*回溯到根节点,从根节点开始按照级联取当前正确的下拉框的对象
  140. 由于下拉框的事件只有一个,而对应的对象有多个,所以这里需要先回溯到根,在从根开始找起
  141. */
  142. this.getRightOnChangeObj = function () {
  143. if (this.parentObj)
  144. return this.parentObj.getRightOnChangeObj().childItem[$('#' + this.parentObj.sourceID).val()]; //递归
  145. else
  146. return this;
  147. }
  148. },
  149. ajaxDropDownBind: {
  150. currentDrop: null,
  151. _thisData: null,
  152. callbackPool: [],
  153. //清理填充项目
  154. clear: function () {
  155. if (_thisData.removeFirst) {
  156. currentDrop.empty();
  157. } else {
  158. for (var i = currentDrop[0].options.length - 1; i > 0; i--) {
  159. currentDrop[0].options[i] = null;
  160. }
  161. }
  162. },
  163. //填充数据项目
  164. fillItem: function () {
  165. for (var i = 0; i < _thisData.items.length; i++) {
  166. var val = _thisData.items[i].length > 1 ? _thisData.items[i][1] : _thisData.items[i][0]; //如果没有指定value则用text代替
  167. currentDrop.append('<option value="' + val + '">' + _thisData.items[i][0] + '</option>');
  168. }
  169. //设置选中项
  170. if (_thisData.selectValue) {
  171. currentDrop.val(_thisData.selectValue);
  172. _thisData.selectValue = '';
  173. }
  174. },
  175. //参数data是指当前变化的下拉框所在的对象
  176. bindData: function (data) {
  177. _thisData = data;
  178. currentDrop = $('#' + _thisData.sourceID); //本身的节点而不是子级
  179. if (_thisData.clearItem)
  180. this.clear();
  181. if (_thisData.items)
  182. this.fillItem();
  183. if (_thisData.childID) {
  184. if (!currentDrop.data('binded')) { //判断是否绑定过事件,绑定过的不在绑定
  185. currentDrop.data('binded', true);
  186. var _firstChangeObj = _thisData; //由于下拉框的事件只有一个,而对应的对象有多个,所以这里的对象是绑定时的对象,而非正确的对象
  187. currentDrop.bind('change', function () {
  188. var rightChildItem = _firstChangeObj.getRightOnChangeObj().childItem;
  189. var thisValue = $('#' + _firstChangeObj.sourceID).val(); //获取当前变化的下拉框的值,注意不能用currentDrop代替,因为currentDrop也是旧的值
  190. if (rightChildItem[thisValue]) {
  191. console.log('cache');
  192. rightChildItem[thisValue].bind(); //使用缓存的数据来绑定
  193. }
  194. else {
  195. console.log('getdata');
  196. //一个新的实例,并建立链表关系
  197. var dropData = new $.ajaxDropDownData();
  198. dropData.sourceID = _firstChangeObj.childID;
  199. dropData.parentObj = _firstChangeObj;
  200. rightChildItem[thisValue] = dropData; //设置缓存
  201. if (_firstChangeObj.callback) //如果有回调函数则直接调用,否则调用系统自动生成的函数
  202. _firstChangeObj.callback(thisValue, dropData); //回调函数
  203. else {
  204. var callback = $.ajaxDropDownBind.callbackPool[dropData.sourceID];
  205. if (callback)
  206. callback(thisValue, dropData);
  207. }
  208. }
  209. });
  210. }
  211. if (_thisData.canChange)
  212. currentDrop.change();
  213. }
  214. },
  215. //绑定第一级下拉框
  216. bindTopDrop: function (sourceID, items, selectValue, removeFirst, childID) {
  217. var mydrop = new $.ajaxDropDownData();
  218. mydrop.sourceID = sourceID;
  219. mydrop.items = items;
  220. if (!items || items.length == 0)
  221. mydrop.clearItem = false;
  222. mydrop.removeFirst = removeFirst;
  223. mydrop.selectValue = selectValue;
  224. mydrop.childID = childID;
  225. mydrop.canChange = false;
  226. mydrop.bind();
  227. },
  228. //绑定子级下拉框
  229. bindCallback: function (sourceID, selectValue, removeFirst, childID, parentPostUrl) {
  230. var callback = function (value, dropdownlist) {
  231. var postData = {};
  232. var parentObj = dropdownlist.parentObj;
  233. while (parentObj) {
  234. postData[parentObj.sourceID] = $('#' + parentObj.sourceID).val();
  235. parentObj = parentObj.parentObj;
  236. }
  237. $.getJSON(parentPostUrl + '&jsoncallback=?', postData, function (data) {
  238. dropdownlist.items = data;
  239. dropdownlist.removeFirst = removeFirst;
  240. dropdownlist.selectValue = selectValue;
  241. dropdownlist.childID = childID;
  242. dropdownlist.bind();
  243. });
  244. };
  245. this.callbackPool[sourceID] = callback;
  246. }
  247. }
  248. });
复制代码

      使用方法代码里有注释,不赘述,欢迎拍砖。

      不知道怎么添加附件,把测试代码也一并贴上来,因为插件二需要服务器端的配合这里就不贴插件二的测试代码。

      插件一测试代码

      复制代码 代码如下:

  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head runat="server">
  4. <title>无限极级联下拉框的封装</title>
  5. <script type="text/JavaScript" src="http://test.fe.ecp.mic.cn/content/scripts/base/jquery.js"></script>
  6. <style>
  7. select
  8. {
  9. margin-left: 10px;
  10. }
  11. body
  12. {
  13. font-size: 14px;
  14. background-color: #CCCCCC;
  15. }
  16. td
  17. {
  18. border: 1px solid #FF6600;
  19. padding: 5px;
  20. text-align: left;
  21. }
  22. input
  23. {
  24. width: 80px;
  25. }
  26. input[type=checkbox]
  27. {
  28. width: 20px;
  29. }
  30. </style>
  31. </head>
  32. <body>
  33. <form id="form1" runat="server">
  34. <div>
  35. <h1>
  36. 无限极级联下拉框的封装</h1>
  37. <div style="margin: 50px 0 50px 10px;">
  38. 绑定方法:<select id="selCase"><option value="1">第一种方法</option>
  39. <option value="2">第二种方法</option>
  40. </select>
  41. <input type="button" onclick="test()" value="绑定" />
  42. <div style="margin: 10px;">
  43. <table cellpadding="0" cellspacing="0">
  44. <tr>
  45. <td>
  46. 第一个下拉框:
  47. </td>
  48. <td>
  49. <input type="text" id="tb1sel" value="a002" />设置当前项的选中值
  50. </td>
  51. <td>
  52. </td>
  53. <td>
  54. </td>
  55. </tr>
  56. <tr>
  57. <td>
  58. 第二个下拉框:
  59. </td>
  60. <td>
  61. <input type="text" id="tb2sel" value="" />设置当前项的选中值
  62. </td>
  63. <td>
  64. <input type="checkbox" id="cb2Remove" value="" />是否移除第一项
  65. </td>
  66. <td>
  67. <input type="text" id="tb2AllValue" value="0" />当前一项值等于此值时,该项全选
  68. </td>
  69. </tr>
  70. <tr>
  71. <td>
  72. 第三个下拉框:
  73. </td>
  74. <td>
  75. <input type="text" id="tb3sel" value="" />设置当前项的选中值
  76. </td>
  77. <td>
  78. <input type="checkbox" id="cb3Remove" />是否移除第一项
  79. </td>
  80. <td>
  81. <input type="text" id="tb3AllValue" value="" />当前一项值等于此值时,该项全选
  82. </td>
  83. </tr>
  84. </table>
  85. </div>
  86. </div>
  87. <h4>
  88. 下拉框结果:</h4>
  89. <div id="selContainer" style="margin: 0px 0 50px 100px;">
  90. </div>
  91. <script type="text/JavaScript" src="/Scripts/Jquery.cascadeDropDown-1.2.js"></script>
  92. <script type="text/JavaScript">
  93. $(function () {
  94. toggleSetting();
  95. $('#selCase').bind('change', toggleSetting);
  96. });
  97. function toggleSetting() {
  98. if ($('#selCase').val() == '1')
  99. $('table tr').each(function (i, item) {
  100. $($(item).find('td')[3]).hide();
  101. });
  102. else
  103. $('table tr').each(function (i, item) {
  104. $($(item).find('td')[3]).show();
  105. });
  106. }
  107. function test() {
  108. if ($('#selCase').val() == '1')
  109. testcase1();
  110. else
  111. testcase2();
  112. }
  113. function testcase1() {
  114. $('#Select1').remove();
  115. $('#Select2').remove();
  116. $('#Select3').remove();
  117. $('#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>');
  118. var dataItem = [['a001', 'a001', '0'], ['a002', 'a002', '0'], ['a003', 'a003', '0']
  119. , ['b001', 'b001', 'a001'], ['b002', 'b002', 'a001'], ['b003', 'b003', 'a002'], ['b004', 'b004', 'a002'], ['b005', 'b005', 'a003']
  120. , ['c001', '001', 'b001'], ['c002', '002', 'b001'], ['c003', '003', 'b002'], ['c004', '004', 'b002'], ['c005', '005', 'b003'], ['c006', '006', 'b004'], ['c007', '007', 'b004'], ['c008', '008', 'b005']
  121. ];
  122. $.cascadeDropDownBind.bind(dataItem,
  123. { sourceID: 'Select1', selectValue: $('#tb1sel').val(), parentValue: '0', removeFirst: false,
  124. child: { sourceID: 'Select2', selectValue: $('#tb2sel').val(), removeFirst: $('#cb2Remove').attr('checked'),
  125. child: { sourceID: 'Select3', selectValue: $('#tb3sel').val(), removeFirst: $('#cb3Remove').attr('checked') }
  126. }
  127. }
  128. );
  129. }
  130. function testcase2() {
  131. $('#Select1').remove();
  132. $('#Select2').remove();
  133. $('#Select3').remove();
  134. //$('#selContainer').html('<select id="Select1"></select><select id="Select2"></select><select id="Select3"></select>');
  135. $('#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>');
  136. var data = [['a001', 'a001'], ['a002', 'a002'], ['a003', 'a003']];
  137. var data2 = [['b001', 'b001', 'a001'], ['b002', 'b002', 'a001'], ['b003', 'b003', 'a002'], ['b004', 'b004', 'a002'], ['b005', 'b005', 'a003']];
  138. 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']];
  139. $.cascadeDropDownBind.bind(data, { sourceID: 'Select1', selectValue: $('#tb1sel').val(), removeFirst: false });
  140. $.cascadeDropDownBind.bind(data2, { sourceID: 'Select2', selectValue: $('#tb2sel').val(), parentID: 'Select1', removeFirst: $('#cb2Remove').attr('checked'), appentAllValue: $('#tb2AllValue').val() });
  141. $.cascadeDropDownBind.bind(data3, { sourceID: 'Select3', selectValue: $('#tb2sel').val(), parentID: 'Select2', removeFirst: $('#cb3Remove').attr('checked'), appentAllValue: $('#tb3AllValue').val() });
  142. }
  143. </script>
  144. </div>
  145. </form>
  146. </body>
  147. </html>
复制代码

相关帖子

发表于 2016-12-13 16:10:51 | 显示全部楼层
纯粹路过,没任何兴趣,仅仅是看在老会员的份上回复一下
使用道具 举报

回复

发表于 2016-12-13 16:10:51 | 显示全部楼层
Very Good!
使用道具 举报

回复

发表于 2016-12-13 16:10:51 | 显示全部楼层
js框架越来越火了, 不过本人还是喜欢原生的好, 自己写类库, 自己来封装,用着方便。。。。
使用道具 举报

回复

发表于 2016-12-13 16:10:51 | 显示全部楼层
前排支持下
使用道具 举报

回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部