BootstrapTable表格数据左右移动功能遇到的问题(数据左右移动,列表拖拽排序,模糊查询列表数据定位)
使用bootstrapTable实现数据左右移动的功能其实做过很多了,但原来实现的功能都是比较单一,都是选中单条数据进行移动。这次需要实现的功能比较全面,中间遇到不少的坑,此次正好在这里将所有的功能代码梳理一下。
实现以下功能:
1.选中单条数据进行左右移动
2.将列表中所有数据全部进行左右移动
3.左边的数据移动到右边后,为其增加一个序号列,并根据右侧列表的数据自动递增序号
4.右侧列表中的数据可以随意拖动排序,序号自动变更
5.在列表上的搜索框输入关键字,定位到列表中对应的数据并选中
html代码:
1 <div class="movebox clearfix box-padding10"> 2 <div class="movebox-left fl"> 3 <p>可选考核项目</p> 4 <div class="form-inline form-inline-auto" style="padding-right: 0;"> 5 <div class="form-group t-right10"> 6 <select class="form-control" style="min-width: 110px" id="kaoheFW" name="kaoheFW"> 7 <option value="2">专科</option> 8 <option value="1">公共</option> 9 </select> 10 </div> 11 <div class="form-control-radio" style="width: auto; min-width: 0;"> 12 <input type="radio" class="radio" name="leixing" value="" checked> 13 <label class="f-left t-right10 t-lineheight28">全部</label> 14 <input type="radio" class="radio" name="leixing" value="2"> 15 <label class="f-left t-right10 t-lineheight28">操作</label> 16 <input type="radio" class="radio" name="leixing" value="1"> 17 <label class="f-left t-right10 t-lineheight28">理论</label> 18 </div> 19 <div class="form-group"> 20 <input class="form-control" placeholder="请输入考核项目" type="text" value="" id="kaoheXM"> 21 </div> 22 </div> 23 <div class="clear"></div> 24 <div class="form-table-height main-y-scroll" id="kaoheXMList"> 25 <table class="table table-striped table-bordered table-hover text-center" id="tableleft"> 26 <thead> 27 28 </thead> 29 <tbody></tbody> 30 </table> 31 </div> 32 <div class="space"></div> 33 </div> 34 <div class="movebox-btn fl"> 35 <span id="add_all" class="icon iconfont icon-youshuangjiantou"></span> 36 <span id="add" class="icon iconfont icon-jiantou-you" onclick="add_keShiKHXM()"></span> 37 <span id="remove" class="icon iconfont icon-jiantou-zuo" onclick="remove_keShiKHXM()"></span> 38 <span id="remove_all" class="icon iconfont icon-zuoshuangjiantou"></span> 39 </div> 40 <div class="movebox-right fl"> 41 <p>已选择考核项目</p> 42 <div class="form-inline form-inline-auto" style="padding-right: 0;"> 43 <div class="form-group t-right10"> 44 <select class="form-control" style="min-width: 110px" id="keshiKHFW" name="keshiKHFW"> 45 <option value="2">专科</option> 46 <option value="1">公共</option> 47 </select> 48 </div> 49 <div class="form-control-radio" style="width: auto; min-width: 0;"> 50 <input type="radio" class="radio" name="keshiLX" value="" checked> 51 <label class="f-left t-right10 t-lineheight28">全部</label> 52 <input type="radio" class="radio" name="keshiLX" value="2"> 53 <label class="f-left t-right10 t-lineheight28">操作</label> 54 <input type="radio" class="radio" name="keshiLX" value="1"> 55 <label class="f-left t-right10 t-lineheight28">理论</label> 56 </div> 57 <div class="form-group" > 58 <input class="form-control" placeholder="请输入考核项目" type="text" value="" id="keshiKHXM" > 59 </div> 60 </div> 61 <div class="clear"></div> 62 <div class="form-table-height main-y-scroll" id="keshiKHXMList"> 63 <table class="table table-striped table-bordered table-hover text-center" id="tableright"> 64 <thead> 65 66 </thead> 67 <tbody> 68 </tbody> 69 </table> 70 </div> 71 <p class="t-gray">说明:拖拽行进行排序</p> 72 </div> 73 </div>
初始化bootstraptable:
1 function Init_kaoHeXM() { 2 3 //获取关键字 4 var kaoHeFW = $('#kaoheFW option:selected').val();; 5 var kaoHeLX = $('input[name="leixing"]:checked').val(); 6 7 $('#tableleft').bootstrapTable("destroy"); 8 //初始化table 9 $('#tableleft').bootstrapTable({ 10 url: "/HLGL/ChengJiGL/GetkaoheXMList", 11 postData: function () { 12 return { "keShiID": keShiID, "kaoHeFW": kaoHeFW, "kaoHeLX": kaoHeLX } 13 }, 14 columns: [ 15 { field: 'KAOHEXMID', title: "考核项目ID", visible: true }, 16 { field: 'XIANGMUMC', title: "项目名称", visible: true }, 17 { field: 'KAOHELX', title: "考核类型", visible: true, formatterType: 'JSON', formatter: { '1': '理论', '2': '操作' } } 18 19 ], 20 pagination: false, 21 autoSelectFirstRow: false, 22 //height: $(window).height() - 117 23 }); 24 } 25 function Init_keShiKHXM() { 26 //获取关键字 27 var kaoHeFW = $('#keshiKHFW option:selected').val();; 28 var kaoHeLX = $('input[name="keshiLX"]:checked').val(); 29 30 $('#tableright').bootstrapTable("destroy"); 31 $('#tableright').bootstrapTable({ 32 url: "/HLGL/ChengJiGL/GetkeshiKHXMList", 33 postData: function () { 34 return { "keShiID": keShiID, "kaoHeFW": kaoHeFW, "kaoHeLX": kaoHeLX } 35 }, 36 columns: [ 37 { field: 'PAIXUXH', title: "排序序号", width: "5%", visible: true, class: "index", }, 38 { field: 'KESHIKHXMID', title: "科室考核项目ID", visible: false }, 39 { field: 'KAOHEXMID', title: "考核项目ID", visible: true }, 40 { field: 'XIANGMUMC', title: "项目名称", visible: true }, 41 { field: 'KAOHELX', title: "考核类型", visible: true, formatterType: 'JSON', formatter: { '1': '理论', '2': '操作' } } 42 43 ], 44 pagination: false,//不分页 45 autoSelectFirstRow: false//默认不选中第一行 46 //height: $(window).height() - 117 47 }) 48 }
初始化后定义了两个变量存放bootstrapTable:
$tableLeft = $('#tableleft').bootstrapTable();
$tableRight = $('#tableright').bootstrapTable();
下面就开始实现第一个功能:选中单条数据进行左右移动 ,右移时增加序号列并在原有基础上递增
这个功能比较简单,没有什么需要注意的地方
1 //添加科室考核项目 2 function add_keShiKHXM() { 3 //注意getSelectedRow这个是内部重新封装的方法,原生获取选中行应该是$("#tableleft").bootstrapTable('getSelections'); 4 var selectContent = $tableLeft.bootstrapTable('getSelectedRow'); 5 if (selectContent == "" || selectContent==null || selectContent == undefined) { 6 HRP.AlertError("请先选择需要操作的数据!"); 7 return false; 8 } 9 selectContent.KESHIID = keShiID; 10 11 //获取到右侧列表的排序序号,给左侧选中行进行设置 12 var len = $('#tableright tr .index').length; 13 if (len == 1) 14 { selectContent.PAIXUXH = 1; } 15 else { 16 selectContent.PAIXUXH = parseInt($('#tableright tr').eq(len - 1).children(0).eq(0)[0].innerText) + 1;//len-1 是因为有标题列 17 } 18 19 20 $tableRight.bootstrapTable("append", selectContent); 21 var selects = $tableLeft.bootstrapTable('getSelectedRow'); 22 23 var KAOHEXMID = selects.KAOHEXMID; 24 25 $tableLeft.bootstrapTable('remove', { 26 field: 'KAOHEXMID', 27 values: [String(KAOHEXMID)] 28 }); 29 30 } 31 32 //移除科室考核项目 33 function remove_keShiKHXM() { 34 //注意getSelectedRow这个是内部重新封装的方法,原生获取选中行应该是$("#tableright").bootstrapTable('getSelections'); 35 var selectContent = $tableRight.bootstrapTable('getSelectedRow'); 36 if (selectContent == "" || selectContent==null || selectContent == undefined) { 37 HRP.AlertError("请先选择需要操作的数据!"); 38 return false; 39 } 40 41 42 $tableLeft.bootstrapTable("append", selectContent); 43 var selects = $tableRight.bootstrapTable('getSelectedRow'); 44 45 var daima = selects.KAOHEXMID; 46 $tableRight.bootstrapTable('remove', { 47 field: 'KAOHEXMID', 48 values: [String(daima)] 49 }); 50 };
第二个功能:将列表所有数据进行左右移动
1 $("#add_all").click(function () { 2 3 if ($("#tableleft tbody tr.no-records-found").length > 0) { 4 HRP.AlertError("当前没有可以操作的数据!"); 5 return false; 6 } 7 $("#tableright tbody tr.no-records-found").remove();//这一句是删除掉表格中没有数据时的提示行 8 // $("#tableright").find(".no-records-found").remove();· 9 var len = 0; 10 if ($("#tableright tbody tr").length == 0) { 11 len = 1; 12 } 13 else { 14 len = parseInt($("#tableright tbody tr:last-child .index").html()) + 1; 15 } 16 17 //下面两个for循环不能合在一起,因为delete以后eq(i)获取的数据会随着改变,不是原来索引的数据 18 for (var i = 0; i < $("#tableleft tbody tr").length; i++) { 19 var content = {"PAIXUXH":len,"KAOHEXMID":$("#tableleft tbody tr").eq(i).find("td")[0].innerText,"XIANGMUMC":$("#tableleft tbody tr").eq(i).find("td")[1].innerText,"KAOHELX":$("#tableleft tbody tr").eq(i).find("td")[2].innerText} 20 $tableRight.bootstrapTable("append", content); 21 len++; 22 } 23 24 //$("#tableleft tbody tr").remove(); 25 //这里不能用remove,此时需要用bootstrapTable自带的删除,否则下次对表进行操作时remove的数据会再次出现 26 // 27 28 var xiangMuLength = $("#tableleft tbody tr").length; 29 for (var j = 0; j < xiangMuLength; j++) { 30 var index = $("#tableleft tbody tr").eq(0).attr("data-index"); 31 $tableLeft.bootstrapTable('deleteRow',index.toNumber()); 32 } 33 }); 34 35 $("#remove_all").click(function () { 36 if ($("#tableright tbody tr.no-records-found").length > 0) { 37 HRP.AlertError("当前没有可以操作的数据!"); 38 return false; 39 } 40 $("#tableleft tbody tr.no-records-found").remove(); 41 $("#tableright tbody td.index").remove(); 42 43 44 //下面两个for循环不能合在一起,因为delete以后eq(i)获取的数据会随着改变,不是原来索引的数据 45 for (var i = 0; i < $("#tableright tbody tr").length; i++) { 46 47 var content = {}; 48 content = {"KAOHEXMID":$("#tableright tbody tr").eq(i).find("td")[0].innerText,"XIANGMUMC":$("#tableright tbody tr").eq(i).find("td")[1].innerText,"KAOHELX":$("#tableright tbody tr").eq(i).find("td")[2].innerText} 49 $tableLeft.bootstrapTable("append", content); 50 } 51 52 var keShiXMLength = $("#tableright tbody tr").length; 53 for (var j = 0; j < keShiXMLength; j++) { 54 55 var index = $("#tableright tbody tr").eq(0).attr("data-index"); 56 $tableRight.bootstrapTable('deleteRow',index.toNumber()); 57 } 58 59 60 });
这里全部数据的左右移动我用的是遍历再使用bootstrapTable的append方法来进行插入,原本我是直接使用的html的appendto方法来进行实现,结果发现存在严重的bug。
通过这种方式虽然在表面上是实现功能了,可以将数据移过去进行保存,但是如果先点击移动全部的按钮将数据转移后,再选中一条数据进行移动,会出现原本列表中被转移的数据会再次出现。经调试发现这种方式虽然被转移了,但数据所属的列表还是原列表,但具体的原理不太清楚。所以后来我通过遍历拼接json字符串最后通过bootstrapTable的append方法进行实现。这样没有出现上面的问题。
下面是我原来的有bug的代码,以后当做反面事例:
$("#add_all").click(function () { if ($("#tableleft tbody tr.no-records-found").length > 0) { HRP.AlertError("当前没有可以操作的数据!"); return false; } $("#tableright tbody tr.no-records-found").remove(); // $("#tableright").find(".no-records-found").remove(); var len = 0; if ($("#tableright tbody tr").length == 0) { len = 1; } else { len = parseInt($("#tableright tbody tr:last-child .index").html()) + 1; } for (var i = 0; i < $("#tableleft tbody tr").length; i++) { var tdNo = "<td class='index'>" + len + "</td>"; $("#tableleft tbody tr").eq(i).prepend(tdNo); len++; } $("#tableleft tbody tr").appendTo($("#tableright tbody")).siblings().removeClass("td-active"); }); $("#remove_all").click(function () { if ($("#tableright tbody tr.no-records-found").length > 0) { HRP.AlertError("当前没有可以操作的数据!"); return false; } $("#tableleft tbody tr.no-records-found").remove(); $("#tableright tbody td.index").remove(); //$("#tableright tbody td:last-child").remove(); $("#tableright tbody tr").appendTo($("#tableleft tbody")).siblings().removeClass("td-active"); });
第三个功能:右侧列表实现拖拽排序
//拖拽排序 var fixHelperModified = function (e, tr) { var $originals = tr.children(); var $helper = tr.clone(); $helper.children().each(function (index) { $(this).width($originals.eq(index).width()) }); return $helper; }, updateIndex = function (e, ui) { $('td.index', ui.item.parent()).each(function (i) { $(this).html(i + 1); }); }; $("#tableright tbody").sortable({ helper: fixHelperModified, stop: updateIndex }).disableSelection();
第四个功能:模糊查询定位数据位置
function dinwei_keShiKHXM() { // 获取搜索框的值 var kwds = $("#keshiKHXM").val(); // 获取第一个列表内容 var this_one = {}; var real_name = ''; // 定义数据列表 var list = $("#tableright tr"); // 定义查找的起始值 var true_one = 0; for (var i = 1; i < list.length; i++) { this_one = $(list[i]); real_name = this_one.text().toString(); // 执行like匹配 if(real_name.match(kwds)){ // 处理第当前的结果 if(true_one == active){ // 获取第一个坐标 var y_len = this_one.offset().top; // 驱动滚动条滚动到指定的位置 $('#keshiKHXMList').mCustomScrollbar('scrollTo', y_len); // 标记当前选中的结果 this_one.addClass('td-active'); this_one.removeClass('on'); }else{ // 标记符合的结果 this_one.addClass('on'); this_one.removeClass('td-active'); } // 累加真实的选择 true_one++; }else{ this_one.removeClass('on'); this_one.removeClass('td-active'); } } // 判断是否搜索完毕 如果搜索完毕 则从第一个开始 否则继续搜索下一个 active = active >= true_one-1 ? 0 : active+1; return false; } function dinwei_kaoHeXM() { // 获取搜索框的值 var kwds = $("#kaoheXM").val(); // 获取第一个列表内容 var this_one = {}; var real_name = ''; // 定义数据列表 var list = $("#tableleft tr"); // 定义查找的起始值 var true_one = 0; for (var i = 1; i < list.length; i++) { this_one = $(list[i]); real_name = this_one.text().toString(); // 执行like匹配 if(real_name.match(kwds)){ // 处理第当前的结果 if(true_one == active){ // 获取第一个坐标 var y_len = this_one.offset().top; // 驱动滚动条滚动到指定的位置 $('#kaoheXMList').mCustomScrollbar('scrollTo', y_len); // 标记当前选中的结果 this_one.addClass('td-active'); this_one.removeClass('on'); }else{ // 标记符合的结果 this_one.addClass('on'); this_one.removeClass('td-active'); } // 累加真实的选择 true_one++; }else{ this_one.removeClass('on'); this_one.removeClass('td-active'); } } // 判断是否搜索完毕 如果搜索完毕 则从第一个开始 否则继续搜索下一个 active = active >= true_one-1 ? 0 : active+1; return false; }
最后就是保存数据了,我因为后台业务原因,只是获取了列表中的主键进行拼接,然后传递到后台进行处理
function Save() { if ($('#tableright').bootstrapTable().find("tbody td.index").length > 0) { var data = null; var tableTRs = $('#tableright').bootstrapTable().find("tbody tr"); if (tableTRs != null && tableTRs != undefined) { for (var i = 0; i < tableTRs.length; i++) { var kaoHeXMID = tableTRs.eq(i).find("td").eq(1).text(); if (i == 0) { data = kaoHeXMID; } else { data += "," + kaoHeXMID; } } } } else { HRP.AlertError("请先选择操作数据,再进行保存!"); return false; } var kaoHeFW = $('#keshiKHFW option:selected').val(); var kaoHeLX = $('input[name="keshiLX"]:checked').val(); postUrl("/HLGL/ChengJiGL/SavekeshiKHXM", { data: data, keShiID: keShiID, kaoHeFW: kaoHeFW,kaoHeLX: kaoHeLX }, function (res) { if (res == true) { HRP.Tip.success("操作成功!"); getParentWindow().doSearch(); closeWin(); } else { HRP.AlertError("操作失败!"); } }) }