layui穿梭框改写,单击时勾选进行穿梭,取消原本穿梭框的中间点击change部分

效果图

在这里插入图片描述

穿梭框组件


/**
 * transfer 穿梭框组件
 */

layui.define(['laytpl', 'form'], function(exports){
  "use strict";

  var $ = layui.$
  ,laytpl = layui.laytpl
  ,form = layui.form

  //模块名
  ,MOD_NAME = 'transferExtend'

  //外部接口
  ,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;
    that.config = $.extend({}, 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(){
        var height = options.height - that.layHeader.outerHeight();
        if(options.showSearch){
          height -= that.laySearch.outerHeight();
        }
        return height - 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 = [];

    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.transfer = function (_index, elem) {
    var that = this
      ,options = that.config
      ,thisBoxElem = that.layBox.eq(_index)
      ,arr = []

    if (!elem) {
      //通过按钮触发找到选中的进行移动
      thisBoxElem.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();
        });
      });
    } else {
      //双击单条记录移动
      var thisList = elem
        ,thisElemCheckbox = thisList.find('input[type="checkbox"]')

      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);
  }

  //事件
  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;
        });
      }

      setTimeout(function () {
        that.renderCheckBtn({stopNone: true});
      }, 0)
    });

    // 双击穿梭
    that.elem.on('dblclick', '.' + ELEM_DATA + '>li', function(event){
      var elemThis = $(this)
        ,thisElemCheckbox = elemThis.children('input[type="checkbox"]')
        ,thisDataElem = elemThis.parent()
        ,thisBoxElem = thisDataElem.parent()

      if(thisElemCheckbox[0].disabled) return;

      that.transfer(thisBoxElem.data('index'), elemThis);
    })
    if (options.clickTrans){
      that.elem.on('click', '.' + ELEM_DATA + '>li', function(event){
        var elemThis = $(this)
          ,thisElemCheckbox = elemThis.children('input[type="checkbox"]')
          ,thisDataElem = elemThis.parent()
          ,thisBoxElem = thisDataElem.parent()

        if(thisElemCheckbox[0].disabled) return;

        that.transfer(thisBoxElem.data('index'), elemThis);
      })
    }


    // 穿梭按钮事件
    that.layBtn.on('click', function(){
      var othis = $(this)
      ,_index = othis.data('index')
      if(othis.hasClass(DISABLED)) return;

      that.transfer(_index);
    });

    //搜索
    that.laySearch.find('input').on('keyup', function(){
      var value = this.value;
      var thisDataElem = $(this).parents('.'+ ELEM_SEARCH).eq(0).siblings('.'+ ELEM_DATA);
      var thisListElem = thisDataElem.children('li');

      thisListElem.each(function(){
        var thisList = $(this);
        var thisElemCheckbox = thisList.find('input[type="checkbox"]');
        var title = thisElemCheckbox[0].title;

        // 是否区分大小写
        if(options.showSearch !== 'cs'){
          title = title.toLowerCase();
          value = value.toLowerCase();
        }

        var isMatch = 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);
});

引入组件

在项目中引入文件,因为layui本身有transfer方法,为了避免冲突,穿梭框改写暴露名称进行修改,引入路 径为transfer文件夹下transfer.js文件,transfer.js文件具体内容如上
在这里插入图片描述

使用transferExtend组件

本页从你传参,并回调给父页面选中的数据,所以使用了loadLayui(),以及getChannelData()方法,如果数据仅在本页使用,不需要包裹方法,script标签内直接写layui.use即可


<style>
    .layuimini-all .layuimini-form{
        padding: 15px !important;
    }
    .layuimini-container, .layuimini-main, .layui-card, #selectStore, #store_transferExtend{
        min-height: 100vh;
        border: none;
    }
    .layui-table-view{
        padding: 0 !important;
    }
    .more-btn{
        top: 10px !important;
    }
    .layui-this{
        background-color:#235fff !important
    }
    .layui-transfer-active{
        display: none;
    }
    .layui-transfer-box[data-index="1"]{
        margin-left: 20px;
    }
    .layui-transfer-box[data-index="0"] .layui-transfer-header{
        display: none;
    }
    .layui-transfer-box[data-index="1"] .layui-transfer-header .layui-form-checkbox{
        padding-left: 10px;
    }
    .layui-transfer-box[data-index="1"] .layui-transfer-header .layui-form-checkbox .layui-icon-ok{
        display: none;
    }
    .layui-transfer-box[data-index="1"] .layui-transfer-search{
        display: none;
    }
    .layui-transfer-box{
        width: 48% !important;
        height: 100vh !important;
    }
    .layui-transfer-data{
        height: 80vh !important;
    }
    .btn-list{
        text-align: center;
    }
</style>
<div class="layuimini-container layuimini-page-anim">
    <div class="layuimini-main">
        <div class="layui-card layui-row">
            <div id="selectStore">
                <div id="store_transferExtend"></div>
            </div>
        </div>
    </div>
</div>
<script>
var addChannelData = [],
curSelectPolicy = ''
function loadLayui () {
    layui.use(['form', 'transferExtend'], function () {
        var form=layui.form;
        var transferExtend = layui.transferExtend;
        var Data = [
            {
                "channel_id":5,
                "title":"渠道1",
                "parent_name_path":"渠道1",
                "parent_id":4,
                "_has_child":0,
                "_level":5
            },
            {
                "channel_id":12,
                "title":"渠道2",
                "parent_name_path":"渠道2",
                "parent_id":4,
                "_has_child":0,
                "_level":5
            },
            {
                "channel_id":9,
                "title":"渠道3",
                "parent_name_path":"渠道3",
                "parent_id":1,
                "_has_child":0,
                "_level":2
            }
        ]
        renderChannel ()

        function renderChannel () {
            var selectedValue = []
            var selectedValue = new Array()
            //父页面选中的数据
			addChannelData = [
				{
	                "channel_id":9,
	                "title":"渠道3",
	                "parent_name_path":"渠道3",
	                "parent_id":1,
	                "_has_child":0,
	                "_level":2
	            }
			]
            //已选择的数据
            if (addChannelData && addChannelData.length > 0) {
                $.each(addChannelData,function(channelIndex,channelItem){
                    selectedValue.push(channelItem.channelId)
                })
            }
            const length = selectedValue.length || 0
            let transTitle = `已选择(${length})`
            transferExtend.render({
                elem: '#store_transferExtend',  //绑定元素
                data:Data,
                value:selectedValue,
                id: 'store_transferExtend',//定义索引
                title: [null, transTitle],
                showSearch: true,
                clickTrans:true,
                parseData: function(res){
                    return {
                    "value": res.channel_id, //数据值
                    "title": res.parent_name_path //数据标题
                    }
                },
                onchange:(data,index)=>{
                    changeHandler(data, index)
                }
            });
            renderDelIcon()
        }

		//点击选择渠道时右侧表格已选择数量发生改变
        function changeHandler(data,index){
            const getData = transferExtend.getData('store_transferExtend');
            const length = getData.length; 
            let transTitle = `已选择(${length})`;
            transferExtend.reload('store_transferExtend', {
                title: [null, transTitle],
                parseData: function(res){
                    return {
                        "value": res.value, //数据值
                        "title": res.title //数据标题
                    }
                },
            });
            renderDelIcon()
        }
        //在右侧选中的数据后增加删除小图标
		function renderDelIcon () {
           var elem = $('.layui-transfer-box[data-index="1"]');
            var ele1 = elem.children().next().next().children()
            for (var i = 0; i < ele1.length; i++) {
                $(ele1[i]).append(`<img src="__STATIC__/images/icon/icon-delete-line.png" class="del-policy-icon icon-delete-line" style="max-width:20px;max-height:20px;">`)
            }
        }

        /* 保存 */
        form.on('submit(applyBtn)', function (data) {
            selectedData = transferExtend.getData('store_transferExtend');
            /* parent.getChannelGoodsData();
            var index = parent.layer.getFrameIndex(window.name); //获取当前窗口的name
            parent.layer.close(index); */
        })
        $('#cancel').click(function () {
            var index = parent.layer.getFrameIndex(window.name); //获取当前窗口的name
            parent.layer.close(index);
        })
    });
}
//获取已选中的数据
function getChannelData () {
    addChannelData = layui.transferExtend.getData('store_transferExtend');
    curSelectPolicy = curSelectPolicy
}
</script>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值