/** @Name:layui.transfer 穿梭框 @Author:贤心 @License:MIT */ layui.define(['laytpl', 'form'], function (exports) { "use strict"; var $ = layui.$ , laytpl = layui.laytpl , form = layui.form //模块名 , MOD_NAME = 'transfer' //外部接口 , transfer = { config: {} , index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0 //设置全局项 , set: function (options) { var that = this; that.config = $.extend({}, that.config, options); return that; } //事件监听 , on: function (events, callback) { return layui.onevent.call(this, MOD_NAME, events, callback); } } //操作当前实例 , thisModule = function () { var that = this , options = that.config , id = options.id || that.index; thisModule.that[id] = that; //记录当前实例对象 thisModule.config[id] = options; //记录当前实例配置项 return { config: options //重置实例 , reload: function (options) { that.reload.call(that, options); } //获取右侧数据 , getData: function () { return that.getData.call(that); } } } //获取当前实例配置项 , getThisModuleConfig = function (id) { var config = thisModule.config[id]; if (!config) hint.error('The ID option was not found in the ' + MOD_NAME + ' instance'); return config || null; } //字符常量 , ELEM = 'layui-transfer', HIDE = 'layui-hide', DISABLED = 'layui-btn-disabled', NONE = 'layui-none' , ELEM_BOX = 'layui-transfer-box', ELEM_HEADER = 'layui-transfer-header', ELEM_SEARCH = 'layui-transfer-search', ELEM_ACTIVE = 'layui-transfer-active', ELEM_DATA = 'layui-transfer-data' //穿梭框模板 , TPL_BOX = function (obj) { obj = obj || {}; return ['
' , '
' , '' , '
' , '{{# if(d.data.showSearch){ }}' , '' , '{{# } }}' , '' , '
'].join(''); } //主模板 , TPL_MAIN = ['
' , TPL_BOX({ index: 0 , checkAllName: 'layTransferLeftCheckAll' }) , '
' , '' , '' , '
' , TPL_BOX({ index: 1 , checkAllName: 'layTransferRightCheckAll' }) , '
'].join('') //构造器 , Class = function (options) { var that = this; that.index = ++transfer.index; that.config = $.extend({}, that.config, transfer.config, options); that.render(); }; //默认配置 Class.prototype.config = { title: ['列表一', '列表二'] , width: 200 , height: 360 , data: [] //数据源 , value: [] //选中的数据 , showSearch: false //是否开启搜索 , id: '' //唯一索引,默认自增 index , text: { none: '无数据' , searchNone: '无匹配数据' } }; //重载实例 Class.prototype.reload = function (options) { var that = this; layui.each(options, function (key, item) { if (item.constructor === Array) delete that.config[key]; }); that.config = $.extend(true, {}, that.config, options); that.render(); }; //渲染 Class.prototype.render = function () { var that = this , options = that.config; //解析模板 var thisElem = that.elem = $(laytpl(TPL_MAIN).render({ data: options , index: that.index //索引 })); var othis = options.elem = $(options.elem); if (!othis[0]) return; //初始化属性 options.data = options.data || []; options.value = options.value || []; //索引 that.key = options.id || that.index; //插入组件结构 othis.html(that.elem); //各级容器 that.layBox = that.elem.find('.' + ELEM_BOX) that.layHeader = that.elem.find('.' + ELEM_HEADER) that.laySearch = that.elem.find('.' + ELEM_SEARCH) that.layData = thisElem.find('.' + ELEM_DATA); that.layBtn = thisElem.find('.' + ELEM_ACTIVE + ' .layui-btn'); //初始化尺寸 that.layBox.css({ width: options.width , height: options.height }); that.layData.css({ height: function () { return options.height - that.layHeader.outerHeight() - that.laySearch.outerHeight() - 2 }() }); that.renderData(); //渲染数据 that.events(); //事件 }; //渲染数据 Class.prototype.renderData = function () { var that = this , options = that.config; //左右穿梭框差异数据 var arr = [{ checkName: 'layTransferLeftCheck' , views: [] }, { checkName: 'layTransferRightCheck' , views: [] }]; //解析格式 that.parseData(function (item) { //标注为 selected 的为右边的数据 var _index = item.selected ? 1 : 0 , listElem = ['
  • ' , '' , '
  • '].join(''); arr[_index].views.push(listElem); delete item.selected; }); // 扩展赋值的顺序跟勾选的顺序一致 var newArr = []; layui.each(options.value, function (index, item1) { layui.each(arr[1].views, function (index2, item2) { var getValue = $(item2).find('input').attr('value'); if (item1 == getValue) { newArr.push(item2); } }); }); // 扩展赋值的顺序跟勾选的顺序一致 end that.layData.eq(0).html(arr[0].views.join('')); that.layData.eq(1).html(newArr.join('')); that.renderCheckBtn(); } //渲染表单 Class.prototype.renderForm = function (type) { form.render(type, 'LAY-transfer-' + this.index); }; //同步复选框和按钮状态 Class.prototype.renderCheckBtn = function (obj) { var that = this , options = that.config; obj = obj || {}; that.layBox.each(function (_index) { var othis = $(this) , thisDataElem = othis.find('.' + ELEM_DATA) , allElemCheckbox = othis.find('.' + ELEM_HEADER).find('input[type="checkbox"]') , listElemCheckbox = thisDataElem.find('input[type="checkbox"]'); //同步复选框和按钮状态 var nums = 0 , haveChecked = false; listElemCheckbox.each(function () { var isHide = $(this).data('hide'); if (this.checked || this.disabled || isHide) { nums++; } if (this.checked && !isHide) { haveChecked = true; } }); allElemCheckbox.prop('checked', haveChecked && nums === listElemCheckbox.length); //全选复选框状态 that.layBtn.eq(_index)[haveChecked ? 'removeClass' : 'addClass'](DISABLED); //对应的按钮状态 //无数据视图 if (!obj.stopNone) { var isNone = thisDataElem.children('li:not(.' + HIDE + ')').length that.noneView(thisDataElem, isNone ? '' : options.text.none); } }); that.renderForm('checkbox'); }; //无数据视图 Class.prototype.noneView = function (thisDataElem, text) { var createNoneElem = $('

    ' + (text || '') + '

    '); if (thisDataElem.find('.' + NONE)[0]) { thisDataElem.find('.' + NONE).remove(); } text.replace(/\s/g, '') && thisDataElem.append(createNoneElem); }; //同步 value 属性值 Class.prototype.setValue = function () { var that = this , options = that.config , arr = []; that.layBox.eq(1).find('.' + ELEM_DATA + ' input[type="checkbox"]').each(function () { var isHide = $(this).data('hide'); isHide || arr.push(this.value); }); options.value = arr; return that; }; //解析数据 Class.prototype.parseData = function (callback) { var that = this , options = that.config , newData = []; layui.each(options.data, function (index, item) { //解析格式 item = (typeof options.parseData === 'function' ? options.parseData(item) : item) || item; newData.push(item = $.extend({}, item)) layui.each(options.value, function (index2, item2) { if (item2 == item.value) { item.selected = true; } }); callback && callback(item); }); options.data = newData; return that; }; //获得右侧面板数据 Class.prototype.getData = function (value) { var that = this , options = that.config , selectedData = []; that.setValue(); layui.each(value || options.value, function (index, item) { layui.each(options.data, function (index2, item2) { delete item2.selected; if (item == item2.value) { selectedData.push(item2); }; }); }); return selectedData; }; //事件 Class.prototype.events = function () { var that = this , options = that.config; //左右复选框 that.elem.on('click', 'input[lay-filter="layTransferCheckbox"]+', function () { var thisElemCheckbox = $(this).prev() , checked = thisElemCheckbox[0].checked , thisDataElem = thisElemCheckbox.parents('.' + ELEM_BOX).eq(0).find('.' + ELEM_DATA); if (thisElemCheckbox[0].disabled) return; //判断是否全选 if (thisElemCheckbox.attr('lay-type') === 'all') { if (options.limit == undefined || options.limit == 0) { thisDataElem.find('input[type="checkbox"]').each(function () { if (this.disabled) return; this.checked = checked; }); } else if (thisElemCheckbox.parent().parent().data('index') != 0) { thisDataElem.find('input[type="checkbox"]').each(function () { if (this.disabled) return; this.checked = checked; }); } } if (options.limit != undefined && options.limit > 0 && checked) { var selectCount = 0; thisDataElem.find('input[type="checkbox"]').each(function () { if (this.checked) { selectCount++; } }); var selectedCount = 0; if (thisElemCheckbox.parent().parent().parent().data('index') == 0) { selectedCount = thisElemCheckbox.parent().parent().parent().next('div').next('div').find('ul li').length; } selectCount += selectedCount; if (options.limit < selectCount) { thisElemCheckbox[0].checked = false; layer.msg('最多选' + options.limit + "个", { icon: 0, time: 1500, shade: 0.3 }); } //获取右侧数据 if (selectedCount == options.limit) { thisElemCheckbox[0].checked = false; layer.msg('最多选' + options.limit + "个", { icon: 0, time: 1500, shade: 0.3 }); } } that.renderCheckBtn({ stopNone: true }); }); //按钮事件 that.layBtn.on('click', function () { var othis = $(this) , _index = othis.data('index') , thisBoxElem = that.layBox.eq(_index) , arr = []; if (othis.hasClass(DISABLED)) return; that.layBox.eq(_index).each(function (_index) { var othis = $(this) , thisDataElem = othis.find('.' + ELEM_DATA); thisDataElem.children('li').each(function () { var thisList = $(this) , thisElemCheckbox = thisList.find('input[type="checkbox"]') , isHide = thisElemCheckbox.data('hide'); if (thisElemCheckbox[0].checked && !isHide) { thisElemCheckbox[0].checked = false; thisBoxElem.siblings('.' + ELEM_BOX).find('.' + ELEM_DATA).append(thisList.clone()); thisList.remove(); //记录当前穿梭的数据 arr.push(thisElemCheckbox[0].value); } that.setValue(); }); }); that.renderCheckBtn(); //穿梭时,如果另外一个框正在搜索,则触发匹配 var siblingInput = thisBoxElem.siblings('.' + ELEM_BOX).find('.' + ELEM_SEARCH + ' input') siblingInput.val() === '' || siblingInput.trigger('keyup'); //穿梭时的回调 options.onchange && options.onchange(that.getData(arr), _index); }); //搜索 that.laySearch.find('input').on('keyup', function () { var value = this.value , thisDataElem = $(this).parents('.' + ELEM_SEARCH).eq(0).siblings('.' + ELEM_DATA) , thisListElem = thisDataElem.children('li'); thisListElem.each(function () { var thisList = $(this) , thisElemCheckbox = thisList.find('input[type="checkbox"]') , isMatch = thisElemCheckbox[0].title.indexOf(value) !== -1; thisList[isMatch ? 'removeClass' : 'addClass'](HIDE); thisElemCheckbox.data('hide', isMatch ? false : true); }); that.renderCheckBtn(); //无匹配数据视图 var isNone = thisListElem.length === thisDataElem.children('li.' + HIDE).length; that.noneView(thisDataElem, isNone ? options.text.searchNone : ''); }); }; //记录所有实例 thisModule.that = {}; //记录所有实例对象 thisModule.config = {}; //记录所有实例配置项 //重载实例 transfer.reload = function (id, options) { var that = thisModule.that[id]; that.reload(options); return thisModule.call(that); }; //获得选中的数据(右侧面板) transfer.getData = function (id) { var that = thisModule.that[id]; return that.getData(); }; //核心入口 transfer.render = function (options) { var inst = new Class(options); return thisModule.call(inst); }; exports(MOD_NAME, transfer); });