懒羊羊
2023-08-30 71e81ed1d12e4d69f53c8ad9e066650ad4186293
提交 | 用户 | 时间
71e81e 1 /**
2  * @ Name:selectPlus 加强版的选择框,可以多选、单选以及通过ulr导入数据
3  * @ Author: YWang
4  * @ License: MIT 
5  */
6
7 layui.define('form', function (exports) {
8   var $ = layui.$,
9     form = layui.form,
10     hint = layui.hint()
11     // 字符常量
12     ,
13     MOD_NAME = 'selectPlus',
14     SELECT = 'layui-form-select',
15     SELECTED = 'layui-form-selected'
16
17     ,
18     selectPlus = {
19       index: layui.selectPlus ? layui.selectPlus.index : 0
20
21         // 设置全局项
22         ,
23       set: function (options) {
24           var that = this;
25           that.config = $.extend({}, that.config, options);
26           return that;
27         }
28
29         // 事件监听
30         ,
31       on: function (events, callback) {
32         return layui.onevent.call(this, MOD_NAME, events, callback);
33       }
34     }
35
36     // 操作当前实例
37     ,
38     thisIns = function () {
39       var that = this,
40         options = that.config;
41
42       return {
43         // 获取数据
44         getChecked: function () {
45           return that.getChecked.call(that);
46         },
47         // 配置数据
48         config: options
49       }
50     }
51
52     // 构造器
53     ,
54     Class = function (options) {
55       var that = this;
56       that.index = ++selectPlus.index;
57       that.config = $.extend({}, that.config, selectPlus.config, options);
58       that.render();
59     };
60
61   //默认配置
62   Class.prototype.config = {
63     type: 'checkbox',
64     valueSeparator: '/',
65     labelSeparator: '  ---  ',
66
67     data: [],
68     valueName: 'title',
69     label: [],
70     values: [],
71
72     url: '',
73     method: 'get',
74     where: '',
75     contentType: '',
76     headers: '',
77     response: 'data',
78     parseData: null,
79
80     config: {
81       checkedName: 'SELECTPLUS_CHECKED',
82       indexName: 'SELECTPLUS_INDEX'
83     },
84
85     error: ''
86
87   };
88   //渲染视图
89   Class.prototype.render = function () {
90     var that = this,
91       options = that.config;
92
93     typeof (options.el) === 'string' ? options.el = $(options.el): options.el;
94     options.reElem = $('<div class="layui-unselect layui-form-select">' +
95       '<div class="layui-select-title">' +
96       '<input type="text" placeholder="请选择" value="" readonly="" class="layui-input layui-unselect">' +
97       '<i class="layui-edge"></i>' +
98       '</div>' +
99       '<dl class="layui-anim layui-anim-upbit">' +
100       '<dd lay-value="" class="layui-select-tips layui-hide">请选择</dd>' +
101       '</dl>' +
102       '</div>');
103
104     // 事件
105     options.reElem.find('.layui-select-title').on('click', function (e) {
106       !$(this).parent().hasClass(SELECTED) ? $(document).find('.' + SELECT).removeClass(SELECTED) : "";
107       $(this).parent().toggleClass(SELECTED);
108     });
109     $(document).on('click', function (e) {
110       ($(e.target).parents('.' + SELECT).length <= 0) && (options.reElem.hasClass(SELECTED)) ? options.reElem.removeClass(SELECTED): "";
111
112     });
113
114
115     !Array.isArray(options.values) ? options.values = [options.values] : "";
116
117     // 查找 表单的 filter
118     options.filter = options.el.parents('.layui-form').attr('lay-filter');
119
120     options.el.append(options.reElem);
121
122
123     if (options.url) { // 获取后端数据
124       this.pullData();
125     } else {
126       that.renderData(); // 数据渲染
127     }
128
129     options.el.on('click', '.layui-select-title', function () {
130       var $title = $(this),
131         $dd0 = $title.next().find('dd').eq(0);
132
133       if (!$dd0.hasClass('layui-hide')) {
134         $dd0.addClass('layui-hide');
135       }
136       $title.find('input').val(options.values.join(options.valueSeparator));
137     })
138
139   }
140
141   Class.prototype.pullData = function () {
142     var that = this,
143       options = that.config;
144     $.ajax({
145       type: options.method || 'get',
146       url: options.url,
147       contentType: options.contentType,
148       data: options.where || {},
149       dataType: 'json',
150       headers: options.headers || {},
151       success: function (res) {
152         //如果有数据解析的回调,则获得其返回的数据
153         if (typeof options.parseData === 'function') {
154           res = options.parseData(res) || res[options.response];
155         }
156         // 如果是数组,则覆盖options.data
157         if (Array.isArray(res)) {
158           options.data = that.formatData(res);
159           options.error = '';
160           that.renderData();
161         } else {
162           options.error = '数据格式不对';
163         }
164       },
165       error: function (e, m) {
166         options.error = '数据接口请求异常:' + m;
167       }
168     });
169
170   }
171
172   // 格式化数据
173   Class.prototype.formatData = function (data) {
174     var that = this,
175       options = that.config,
176       valueName = options.valueName,
177       values = options.values,
178       checkedName = options.config.checkedName,
179       indexName = options.config.indexName;
180
181     layui.each(data, function (i, item) {
182       if (typeof item !== 'object') {
183         data[i] = {
184           title: item
185         }
186       }
187       data[i][indexName] = i;
188       if (!data[i][checkedName]) data[i][checkedName] = false;
189       layui.each(values, function (index, value) {
190         if (data[i][valueName] === value) {
191           data[i][checkedName] = true;
192         }
193       })
194     });
195     values.splice(0);
196
197
198
199     return data;
200   }
201
202
203   // 渲染数据
204   Class.prototype.renderData = function (data) {
205     var that = this,
206       options = that.config,
207       type = options.type,
208       id = that.index,
209       data = data ? that.formatData(data) : that.formatData(options.data)
210
211
212
213     items = {
214
215       // 多选
216       checkbox: function (config, data, id) {
217         var CLASSNAME = 'layui-form-checkbox',
218           CHECKED = 'layui-form-checked',
219
220           el = config.reElem.find('dl'),
221           valueName = config.valueName,
222           checkedName = config.config.checkedName,
223           indexName = config.config.indexName,
224           values = config.values,
225           label = config.label,
226           filter = config.filter,
227           labelSeparator = config.labelSeparator,
228           valueSeparator = config.valueSeparator,
229
230           sum = 0;
231
232
233         // 添加选项
234         el.append($('<dd lay-value="全选"></dd>'));
235         layui.each(data, function (i, item) {
236           el.append($('<dd lay-value="' + item[valueName] + '"></dd>'));
237         })
238
239
240         var allEle = el.find('dd').eq(1);
241
242         // 添加多选框
243
244         allEle.nextAll().each(function (index) {
245           var $dd = $(this),
246             item = data[index],
247             layuiValue = item[valueName],
248             title = layuiValue;
249           if (label.length > 0) {
250             title = "";
251             layui.each(label, function (i, n) {
252               title += item[n];
253               i < (label.length - 1) ? title += labelSeparator : '';
254             })
255           }
256           var checkbox = $('<input type="checkbox" name="' + MOD_NAME + 'checkbox' + id + '"  yw-index="' + item[indexName] + '" lay-skin="primary" title="' + title + '" layui-value="' + layuiValue + '">');
257           if (item[checkedName]) {
258             checkbox.prop('checked', true);
259             values.push(layuiValue);
260             sum++;
261           }
262           $dd.html(checkbox);
263         })
264
265         var allcheckbox = $('<input type="checkbox"  selectplus-all  lay-skin="primary" title="全选" layui-value="全选">');
266         sum === data.length ? allcheckbox.prop('checked', true) : "";
267         allEle.html(allcheckbox);
268
269         allEle.parent().prev().find('input').val(values.join(valueSeparator));
270
271         // 添加事件
272         allEle.on('click', function (event) {
273           var $all = $(this),
274             checked = event.target.nodeName === 'DD' ? $all.find('.' + CLASSNAME).toggleClass(CHECKED).hasClass(CHECKED) : $all.find('input').prop('checked');
275
276           // 禁止下拉框收回
277           $all.parents('.' + SELECT).addClass(SELECTED);
278
279           // 设置选中状态 
280           $all.find('input').prop('checked', checked);
281
282           $all.nextAll().each(function () {
283             var dd = $(this);
284             checked ? dd.find('.' + CLASSNAME).addClass(CHECKED) : dd.find('.' + CLASSNAME).removeClass(CHECKED);
285             dd.find('input').prop('checked', checked);
286           })
287
288
289           // 显示选中数据
290           layui.event.call($all, MOD_NAME, 'checkbox' + '(' + MOD_NAME + ')', {
291             type: "checkbox",
292             ele: $all,
293             eleChecked: checked,
294             isAll: checked
295           });
296
297         })
298         allEle.nextAll().on('click', function (e) {
299           var $dd = $(this),
300             checked = event.target.nodeName === 'DD' ? $dd.find('.' + CLASSNAME).toggleClass(CHECKED).hasClass(CHECKED) : $dd.find('input').prop('checked');
301
302           // 禁止下拉框收回
303           $dd.parents('.' + SELECT).addClass(SELECTED);
304
305           // 设置选中状态
306           $dd.find('input').prop('checked', checked);
307
308           // 判断全选
309           var $all = $dd.parents('dl').find('dd').eq(1),
310             $dds = $all.nextAll(),
311             sum = 0;
312           $dds.each(function () {
313             $(this).find('input').prop('checked') ? sum++ : '';
314           })
315
316           if (sum === $dds.length) {
317             $all.find('input').prop('checked', true);
318             $all.find('.' + CLASSNAME).addClass(CHECKED);
319           } else {
320             $all.find('input').prop('checked', false);
321             $all.find('.' + CLASSNAME).removeClass(CHECKED);
322           }
323
324           // 显示选中数据
325           layui.event.call($all, MOD_NAME, 'checkbox' + '(' + MOD_NAME + ')', {
326             type: "checkbox",
327             ele: $dd,
328             eleChecked: checked,
329             isAll: (sum === $dds.length)
330           });
331
332           // 阻断事件
333           event.stopPropagation();
334         })
335
336         // 渲染多选框
337         // el.next().find('dl').addClass('yw-selectPlus');
338         form.render('checkbox', filter);
339
340       },
341
342       // 单选
343       radio: function (config, data, id) {
344         var CLASSNAME = 'layui-form-radio',
345           CHECKED = 'layui-form-radioed',
346           ICON = ['&#xe643;', '&#xe63f;'],
347           CHECKED_ICON = 'layui-anim-scaleSpring',
348
349           elID = config.el,
350           el = config.reElem.find('dl'),
351           valueName = config.valueName,
352           checkedName = config.config.checkedName,
353           indexName = config.config.indexName,
354           checkedData = data.filter(function (item) {
355             return item[checkedName] === true;
356           }),
357           values = config.values,
358           label = config.label,
359           filter = config.filter,
360           labelSeparator = config.labelSeparator,
361           valueSeparator = config.valueSeparator;
362
363
364         // 添加选项
365         layui.each(data, function (i, item) {
366           el.append('<dd lay-value="' + item[valueName] + '"></dd>');
367         })
368         form.render('select', options.filter);
369
370
371         // 渲染单选框
372         el.find('dd').eq(0).nextAll().each(function (index) {
373           var $dd = $(this),
374             item = data[index],
375             layuiValue = item[valueName],
376             title = layuiValue;
377           if (label.length > 0) {
378             title = "";
379             layui.each(label, function (i, n) {
380               title += item[n];
381               i < (label.length - 1) ? title += labelSeparator : '';
382             })
383           }
384
385           var dd = $('<input type="radio" name="' + MOD_NAME + 'radio' + id + '"  yw-index="' + item[indexName] + '" lay-skin="primary" title="' + title + '" layui-value="' + layuiValue + '">');
386
387           if (checkedData.length > 0 && checkedData[0][indexName] === item[indexName]) {
388             dd.prop('checked', true);
389             values.push(layuiValue);
390             $dd.parent().prev().find('input').val(values.join(valueSeparator))
391           }
392           $dd.html(dd);
393         })
394
395
396         // el.next().find('dl').addClass('yw-selectPlus');
397         form.render('radio', filter);
398
399         // 事件
400         el.find('dd').on('click', function (event) {
401           var $dd = $(this);
402           $dd.find('.' + CLASSNAME).addClass(CHECKED).find('i').addClass(CHECKED_ICON).html(ICON[0]);
403           $dd.find('input').prop('checked', true);
404           $dd.siblings().find('.' + CLASSNAME).removeClass(CHECKED).find('i').removeClass(CHECKED_ICON).html(ICON[1]);
405           $dd.siblings().find('input').prop('checked', false);
406           // 显示选中数据
407           layui.event.call($dd, MOD_NAME, 'radio' + '(' + MOD_NAME + ')', {
408             type: "radio",
409             ele: $dd,
410             eleChecked: true,
411             isAll: false
412           });
413         })
414       }
415
416
417     };
418
419     // 选择时触发的事件
420     layui.onevent.call(that, MOD_NAME, type + '(' + MOD_NAME + ')', that.checked.bind(that));
421
422     items[type] ? items[type](options, data, id) : hint.error('不支持的' + type + '表单渲染');
423
424   }
425
426   // 选中数据处理
427   Class.prototype.checked = function (res) {
428     var that = this,
429       options = that.config,
430       data = options.data,
431       checkedName = options.config.checkedName,
432       type = res.type,
433       isAll = res.isAll,
434       ele = res.ele,
435       eleChecked = res.eleChecked,
436       filter = options.el.attr('lay-filter');
437
438     if (type === 'checkbox') {
439       options.values = [];
440       ele.parents('dl').find('[type="checkbox"]').each(function (i) {
441         var $dd = $(this),
442           ywIndex = $dd.attr('yw-index'),
443           checked = $dd.prop('checked');
444         ywIndex ? data[ywIndex][checkedName] = checked : "";
445         checked && ywIndex ? options.values.push($dd.attr('layui-value')) : "";
446       })
447
448       ele.parent().prev().find('input').val(options.values.join(options.valueSeparator));
449
450       layui.event.call(ele, MOD_NAME, MOD_NAME + '(' + filter + ')', {
451         checked: eleChecked,
452         isAll: isAll,
453         values: options.values,
454         checkedData: data.filter(function (item) {
455           return item[checkedName] === true;
456         }),
457         ele: ele
458       });
459     } else if (type === 'radio') {
460       var index = ele.find('input').attr('yw-index'),
461         value = ele.find('input').attr('layui-value');
462
463       options.values = [value];
464       ele.parent().prev().find('input').val(value);
465
466       layui.each(data, function (i, item) {
467         item[checkedName] = false;
468       })
469
470       data[index][checkedName] = true;
471
472       layui.event.call(ele, MOD_NAME, MOD_NAME + '(' + filter + ')', {
473         value: value,
474         checkedData: data[index],
475         ele: ele
476       });
477     }
478
479   }
480
481   // 获取选中数据
482   Class.prototype.getChecked = function () {
483     var that = this,
484       options = that.config,
485       data = options.data,
486       checkedName = options.config.checkedName;
487
488     return {
489       values: options.values,
490       data: data.filter(function (item) {
491         return item[checkedName] === true;
492       })
493     };
494   }
495
496   // 核心入口
497   selectPlus.render = function (options) {
498     var ins = new Class(options);
499     return thisIns.call(ins);
500   };
501   exports('selectPlus', selectPlus);
502 })