bootStrap树形目录组件

时间:2024-04-16 13:45:22

需求描述

产品添加页面,需要选择车型。在bootStrap的modal上弹出子modal来使用。
车型一共有4级目录。要使用目录树。
然后分活动和商品两种,需要能够通过不通参数来调用该组件。
车型品牌要使用字母导航。

 

技术实现

数据都是后端传json过来,我们ajax获取然后操作。
由于车型总数据有几万条以上,不可能一次性请求过来。这里我们使用异步的方式,每点击一次目录节点,加载它的下一级。
这里我们用两个参数来控制活动和商品的不同加载。_showPrice和opened
后端传过来的第一级数据是车型品牌,其中有首字母的字段。字母导航的初始化,就是把这个数据用firstWord属性来排序,然后忽略掉其他首字母相同的元素。
对于活动类型,需要返回所勾选的最低一级的数据。(勾选奥迪和奥迪A6,则只返回A6的意思),这里用了整整4层循环。不过它是根据是否有checked来遍历的,速度不慢。

 

  1 /**
  2  * Created by nuenfeng on 2016/5/23.
  3  * 车型选择组件
  4  * 参数:
  5  * showPrice 是否要输入价格(不输入价格的从品牌开始就有选项框,没有全选功能)
  6  * params 外部传入的对象
  7  * callback 回调函数
  8  */
  9 (function () {
 10     var uriCarBrand = global.url.carBrandList;
 11     //var uri = uriCarBrand.url;
 12     var opened = false; //当前页面是否打开过本组件
 13     var _callback;      //回调函数
 14     var requestParams;  //请求时要使用的参数
 15     var _showPrice;     //是否要输入价格
 16     var lastShowPrice;  //前一次打开状态
 17     var charNavArr;     //字母导航数组
 18 
 19     function CarTree(showPrice, params, callback) {
 20         // 没打开过,初始化; 打开过,直接显示modal
 21         requestParams = params;
 22         _showPrice = showPrice;
 23         _callback = callback;
 24 
 25         if (!opened || lastShowPrice != showPrice) {
 26             this.init();
 27             opened = true;
 28             lastShowPrice = showPrice;
 29         } else {
 30             $(\'#zc-sub-modal\').modal(\'show\');
 31         }
 32     }
 33 
 34     CarTree.prototype.init = function () {
 35 
 36         msjcTools.addSubModal();
 37         //设置大模态框
 38         $(\'#zc-sub-modal\').addClass("bs-example-modal-lg");
 39         $(\'#zc-sub-modal .modal-dialog\').addClass("modal-lg");
 40 
 41         var str = \'<form id="info-form" data-parsley-validate class="form-horizontal form-label-left">\';
 42         str += \'<ul id="resourceId" class="treeview-gray">\'
 43         str += \'<li id="cb_0"><span>汽车品牌选择</span>\';
 44         str += "</li>"
 45         str += \'</ul>\'
 46         str += \'</form>\';
 47 
 48         var objId = \'cb_0\';
 49         var carBrandId = 0;
 50         loadSubMenu(objId, carBrandId, 1);  //1 表示第一次加载,用于加载成功后判断时候要初始化字母导航
 51 
 52         $(\'#zc-sub-modal-body\').html(str);
 53         $(\'#zc-sub-modal\').modal({
 54             keyboard: false,
 55             show: true
 56         });
 57 
 58         // 点击保存事件
 59         $(\'#zc-sub-modal .modal-footer .btn.btn-primary\').unbind().bind("click", function () {
 60             save();
 61         });
 62 
 63 
 64         //$("#resourceId").find("input[type=checkbox]").unbind().bind("click",function(){
 65         //    if($(this).is(\':checked\')==true){//选中 则其上层节点全部展开并选中
 66         //        //上级选中
 67         //        $(this).parents("li").each(function(){
 68         //            $(this).find("input[type=checkbox]:first").attr("checked",true)
 69         //        });
 70         //    } else {
 71         //        //下级取消选中
 72         //        $(this).siblings("ul").find("input[type=checkbox]").each(function(){
 73         //            $(this).removeAttr("checked");
 74         //        });
 75         //    }
 76         //});
 77 
 78 
 79         //隐藏子窗口后 保持父窗口的滚动
 80         $("#zc-sub-modal").on("hidden.bs.modal", function () {
 81             $(\'body\').addClass(\'modal-open\')
 82         });
 83     }
 84 
 85     CarTree.prototype.empty = function () {
 86         opened = false;
 87         console.log(\'empty me\');
 88     }
 89 
 90     //加载子菜单
 91     var loadSubMenu = function (objId, carBrandId, times) {
 92 
 93         requestParams.brandId = carBrandId;
 94         executeAjax(global.url.carBrandList, requestParams, function (data) {
 95             // 给data风骚地排个序
 96             data.sort(keysrt("firstWord"));
 97 
 98             var menuHtml = "<ul>";
 99             for (var index in data) {
100                 var menu = data[index];
101                 menuHtml += \'<li id="cb_\' + menu.carBrandId + \'" value="\' + menu.carBrandId + \'" brand="\' + menu.brand + \'">\';
102 
103                 // 带价格的树
104                 if (_showPrice) {
105                     // 最后一级,添加选项框
106                     if (menu.level > 3) {
107                         menuHtml += \'<input type="checkbox" name="resourceIds" value="\' + menu.carBrandId + \'" />\';
108                     }
109                     menuHtml += \'<span>\' + menu.name + \'</span>\';
110 
111                     // 最后一级,添加输入框
112                     if (menu.level == 4) {
113                         menuHtml += \'<input type="text" maxlength="9">\';
114                     }
115                 } else { // 不带价格的树
116                     menuHtml += \'<input type="checkbox" name="resourceIds" value="\' + menu.carBrandId + \'" />\';
117                     menuHtml += \'<span>\' + menu.name + \'</span>\';
118                 }
119 
120                 menuHtml += "</li>";
121             }
122             menuHtml += "</ul>";
123             $(\'#\' + objId).append(menuHtml);
124             $(\'#\' + objId).attr(\'data-load\', \'loaded\');
125 
126             //汽车类型第一级加载完成后,初始化字符导航
127             charNavArr = [];
128             var fwdLast = \'\';    //上一次的首字母
129 
130             for (var i in data) {
131                 var cobjTemp = {};
132                 if (fwdLast != data[i].firstWord) {
133                     fwdLast = data[i].firstWord;
134                     cobjTemp.firstWord = fwdLast;
135                     cobjTemp.targetId = \'cb_\'+data[i].carBrandId;
136                     charNavArr.push(cobjTemp);
137                 }
138             }
139             if (times == 1) {
140                 initCharNav();
141                 // 点击保存事件
142                 $(\'.charNavSaveBtn\').unbind().bind("click", function () {
143                     save();
144                 });
145             }
146         });
147 
148     }
149 
150     // 此处是风骚的数组对象排序
151     var keysrt = function (propertyName) {
152         return function (object1, object2) {
153             var value1 = object1[propertyName];
154             var value2 = object2[propertyName];
155             if (value2 < value1) {
156                 return 1;
157             }
158             else if (value2 > value1) {
159                 return -1;
160             }
161             else {
162                 return 0;
163             }
164         }
165     }
166 
167     // 保存事件
168     var save = function(){
169         // 确认后,执行回调函数
170         if (_showPrice) {
171             var res = getPriceResult();
172             if (res.status) {
173                 _callback(res.data);
174             } else {
175                 alert(res.error);
176                 return;
177             }
178         } else {
179             _callback(getNopriceResult());
180         }
181         //返回数据,然后隐藏
182         $(\'#zc-sub-modal\').modal(\'hide\');
183     }
184 
185     // 设置字符导航初始化
186     var initCharNav = function () {
187         var charNavHtml = \'<ul id="charNavBar" class="charNavBar pagination">\';
188         for (var i in charNavArr) {
189             charNavHtml += \'<li><a href="#\'+charNavArr[i].targetId+\'">\'+charNavArr[i].firstWord+\'</a></li>\';
190         }
191         charNavHtml += \'<li><a class="modalGoTop">↑</a></li>\';
192         charNavHtml += \'<button type="button" class="btn btn-primary charNavSaveBtn">保存</button>\';
193         charNavHtml += \'</ul>\';
194 
195         $(\'#zc-sub-modal\').append(charNavHtml);
196 
197         $(\'.modalGoTop\').on(\'click\', function(e){
198             $(\'#zc-sub-modal\').animate({scrollTop: 0}, 500);
199         });
200     }
201 
202     // 统计带价格的返回数据
203     var getPriceResult = function () {
204         var result = {
205             status : true,
206             data : [],
207             error : \'\'
208         };
209         var liTemp;
210         var objTemp;
211         $(\'.treeview-gray input:checkbox:checked\').each(function (i) {
212             liTemp = $(this).parent(\'li\');
213             objTemp = {};
214             objTemp.carBrandId = liTemp.attr(\'value\');
215             objTemp.brand = liTemp.attr(\'brand\');
216             objTemp.carBrandName = liTemp.find(\'span\').text();
217             objTemp.unitPrice = liTemp.find(\'input:text\').val();
218 
219             // 如果价格没有输入,返回保存失败,并返回没有输入的carBrandName
220             if(objTemp.unitPrice == \'\') {
221                 result.status = false;
222                 result.error = \'请输入 \' + objTemp.carBrandName + \' 的价格!\';
223                 return result;
224             }
225             result.data.push(objTemp);
226         });
227         return result;
228     }
229 
230     // 统计不带价格的返回数据
231     var getNopriceResult = function () {
232         var result = [];
233         var liTemp;
234         var objTemp;
235         var flag1;
236         var flag2;
237         var flag3;
238         var flag4;
239         var level2Name;
240 
241         // 遍历4层
242         $(\'#cb_0\').children().children(\'li\').children(\'input:checkbox\').each(function (i1) {
243             if ($(this).is(\':checked\')) {
244                 flag1 = true;
245             } else {
246                 flag1 = false;
247             }
248             $(this).parent().children().children(\'li\').children(\'input:checkbox\').each(function (i2) {
249                 if ($(this).is(\':checked\')) {
250                     flag1 = false;
251                     flag2 = true;
252                 } else {
253                     flag2 = false;
254                 }
255                 // 获取第二级的名字,给第三级使用
256                 liTemp = $(this).parent(\'li\');
257                 level2Name = liTemp.children(\'span\').text();
258                 $(this).parent().children().children(\'li\').children(\'input:checkbox\').each(function (i3) {
259                     if ($(this).is(\':checked\')) {
260                         flag1 = false;
261                         flag2 = false;
262                         flag3 = true;
263                     } else {
264                         flag3 = false;
265                     }
266                     $(this).parent().children().children(\'li\').children(\'input:checkbox\').each(function (i4) {
267                         if ($(this).is(\':checked\')) {
268                             flag1 = false;
269                             flag2 = false;
270                             flag3 = false;
271                             flag4 = true;
272                         } else {
273                             flag4 = false;
274                         }
275                         if (flag4) {
276                             liTemp = $(this).parent(\'li\');
277                             objTemp = {};
278                             objTemp.carBrandId = liTemp.attr(\'value\');
279                             objTemp.brand = liTemp.attr(\'brand\');
280                             //objTemp.carBrandName = liTemp.children(\'span\').text();
281                             objTemp.carBrandName = objTemp.brand + \' \' + liTemp.children(\'span\').text();
282                             result.push(objTemp);
283                         }
284                     });
285                     if (flag3) {
286                         liTemp = $(this).parent(\'li\');
287                         objTemp = {};
288                         objTemp.carBrandId = liTemp.attr(\'value\');
289                         objTemp.brand = liTemp.attr(\'brand\');
290                         //objTemp.carBrandName = liTemp.children(\'span\').text();
291                         objTemp.carBrandName = objTemp.brand + \' \' + level2Name + \' \' + liTemp.children(\'span\').text();
292                         result.push(objTemp);
293                     }
294                 });
295                 if (flag2) {
296                     //liTemp = $(this).parent(\'li\');
297                     objTemp = {};
298                     objTemp.carBrandId = liTemp.attr(\'value\');
299                     objTemp.brand = liTemp.attr(\'brand\');
300                     //objTemp.carBrandName = objTemp.brand + liTemp.children(\'span\').text();
301                     objTemp.carBrandName = objTemp.brand + \' \' + liTemp.children(\'span\').text();
302                     result.push(objTemp);
303                 }
304             });
305             if (flag1) {
306                 liTemp = $(this).parent(\'li\');
307                 objTemp = {};
308                 objTemp.carBrandId = liTemp.attr(\'value\');
309                 objTemp.brand = liTemp.attr(\'brand\');
310                 objTemp.carBrandName = liTemp.children(\'span\').text();
311                 result.push(objTemp);
312             }
313         });
314 
315         return result;
316     }
317 
318 
319     // 给目录树绑定点击事件
320     $(document).on(\'click\', \'#resourceId li\', function (e) {
321 
322 
323         e.stopPropagation();
324 
325         if ($(this).attr(\'open\')) {
326             $(this).removeAttr(\'open\');
327             $(this).children(\'ul\').hide();
328         } else {
329             $(this).attr(\'open\', \'opened\');
330             $(this).children(\'ul\').show();
331         }
332         var objId = $(this).attr(\'id\');
333         var carBrandId = $(this).attr(\'value\');
334         //加载过的不执行
335         if ($(this).attr(\'data-load\')) {
336             return;
337         }
338         loadSubMenu(objId, carBrandId);
339     });
340 
341     // 点击多选框时候不下拉
342     $(document).on(\'click\', \'input[type="checkbox"]\', function (e) {
343         e.stopPropagation();
344     });
345 
346     window.CarTree = CarTree;
347 }());

 

调用方法:

carTree = new CarTree(false, {}, function (data) {
    console.log(data);
 });