123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- /**
-
- @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 ['<div class="layui-transfer-box" data-index="'+ obj.index +'">'
- ,'<div class="layui-transfer-header">'
- ,'<input type="checkbox" name="'+ obj.checkAllName +'" lay-filter="layTransferCheckbox" lay-type="all" lay-skin="primary" title="{{ d.data.title['+ obj.index +'] || \'list'+ (obj.index + 1) +'\' }}">'
- ,'</div>'
- ,'{{# if(d.data.showSearch){ }}'
- ,'<div class="layui-transfer-search">'
- ,'<i class="layui-icon layui-icon-search"></i>'
- ,'<input type="input" class="layui-input" placeholder="关键词搜索">'
- ,'</div>'
- ,'{{# } }}'
- ,'<ul class="layui-transfer-data"></ul>'
- ,'</div>'].join('');
- }
-
- //主模板
- ,TPL_MAIN = ['<div class="layui-transfer layui-form layui-border-box" lay-filter="LAY-transfer-{{ d.index }}">'
- ,TPL_BOX({
- index: 0
- ,checkAllName: 'layTransferLeftCheckAll'
- })
- ,'<div class="layui-transfer-active">'
- ,'<button type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="0">'
- ,'<i class="layui-icon layui-icon-next"></i>'
- ,'</button>'
- ,'<button type="button" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="1">'
- ,'<i class="layui-icon layui-icon-prev"></i>'
- ,'</button>'
- ,'</div>'
- ,TPL_BOX({
- index: 1
- ,checkAllName: 'layTransferRightCheckAll'
- })
- ,'</div>'].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 = ['<li>'
- ,'<input type="checkbox" name="'+ arr[_index].checkName +'" lay-skin="primary" lay-filter="layTransferCheckbox" title="'+ item.title +'"'+ (item.disabled ? ' disabled' : '') + (item.checked ? ' checked' : '') +' value="'+ item.value +'">'
- ,'</li>'].join('');
- arr[_index].views.push(listElem);
- delete item.selected;
- });
-
- that.layData.eq(0).html(arr[0].views.join(''));
- that.layData.eq(1).html(arr[1].views.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 = $('<p class="layui-none">'+ (text || '') +'</p>');
- 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 = [];
- 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'){
- thisDataElem.find('input[type="checkbox"]').each(function(){
- if(this.disabled) return;
- this.checked = checked;
- });
- }
-
- 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);
- });
|