bootStrap树形目录组件
需求描述
产品添加页面,需要选择车型。在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);
});

浙公网安备 33010602011771号