博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
JS组件系列——Bootstrap Table 表格行拖拽(二:多行拖拽)
阅读量:7009 次
发布时间:2019-06-28

本文共 19456 字,大约阅读时间需要 64 分钟。

前言:前天刚写了篇,今天接到新的需要,需要在之前表格行拖拽的基础上能够同时拖拽选中的多行。博主用了半天时间研究了下,效果是出来了,但是感觉不尽如人意。先把它分享出来,以后想到更好的办法再优化吧。

一、效果展示

1、拖动前

 

2、拖动中

3、拖动后

4、撤销回到拖动前状态

 

二、需求分析

通过上篇我们知道,如果要实现拖拽,必须要有一个可以拖拽的标签,或者叫容器,比如上篇里面的tr就是一个拖拽的容器,那么如果要实现选择行的拖拽,那么博主的第一反应是将选中的行放到一个容器里面,比如放到一个div中,然后注册这个div的可拖拽,可是实际情况是,tr是在table里面的标签,如果将tr用div包起来,势必将table里面的样式打乱,这个界面就真的是乱掉了。很显然,这条路走不通。然后通过谷歌浏览器审核元素知道,用Bootstrap table生成的表格tr的父级元素实际上是tbody,于是在想是否可以注册tbody的拖拽,实践证明,此法可行。于是就此开干。

三、代码示例

cshtm的代码就不再重复,和上篇相同。我们重点来看看js代码。

var i_statuindex = 0;var arrdata = [];var m_oTable = null;$(function () {    //1.初始化表格    m_oTable = new TableInit();    m_oTable.Init();    //2.初始化按钮事件    var oButtonInit = new ButtonInit();    oButtonInit.Init();    //3.日期控件的初始化    $(".datetimepicker").datetimepicker({        format: 'yyyy-mm-dd hh:ii',        autoclose: true,        todayBtn: true,    });});//表格相关事件和方法var TableInit = function () {    var oTableInit = new Object();    oTableInit.Init = function () {        $('#tb_order_left').bootstrapTable({            url: '/api/OrderApi/get',            method: 'get',            striped: true,            cache: false,            striped: true,            pagination: true,            height: 600,            uniqueId:"TO_ORDER_ID",            queryParams: oTableInit.queryParams,            queryParamsType: "limit",            sidePagination: "server",            pageSize: 10,            pageList: [10, 25, 50, 100],            search: true,            strictSearch: true,            showColumns: true,            showRefresh: true,            minimumCountColumns: 2,            clickToSelect: true,            columns: [{                checkbox: true            },            {                field: 'ORDER_NO',                title: '订单号'            },            {                field: 'BODY_NO',                title: '车身号'            }, {                field: 'VIN',                title: 'VIN码'            }, {                field: 'TM_MODEL_MATERIAL_ID',                title: '整车编码'            },            {                field: 'ORDER_TYPE',                title: '订单类型'            },            {                field: 'ORDER_STATUS',                title: '订单状态'            },            {                field: 'CREATE_DATE',                title: '订单导入时间'            },            {                field: 'PLAN_DATE',                title: '订单计划上线日期'            },            {                field: 'VMS_NO',                title: 'VMS号'            },            {                field: 'ENGIN_CODE',                title: '发动机号'            },            {                field: 'TRANS_CODE',                title: '变速箱号'            },            {                field: 'OFFLINE_DATE_ACT',                title: '实际下线日期'            },            {                field: 'HOLD_RES',                title: 'hold理由'            },            {                field: 'SPC_FLAG',                title: '特殊标记'            },            ],            onLoadSuccess: function (data) {                oTableInit.InitDrag();                if (data.total > 0) {                    var iheight = $('#div_tableleft').find(".fixed-table-container").height();                    $('#div_tableleft').find(".fixed-table-container").height(iheight + 36);                }            },            onCheckAll: function (rows) {                $("#tb_order_left tbody tr").addClass("selected");            },            onUncheckAll: function (rows) {                $("#tb_order_left tbody tr").removeClass("selected");            }        });        $('#tb_order_right').bootstrapTable({            url: '/api/OrderApi/get',            method: 'get',            toolbar: '#toolbar_right',            striped: true,            cache: false,            striped: true,            pagination: true,            height: 600,            queryParams: oTableInit.queryParamsRight,            queryParamsType: "limit",            //ajaxOptions: { departmentname: "", statu: "" },            sidePagination: "server",            pageSize: 10,            pageList: [10, 25, 50, 100],            search: true,            strictSearch: true,            showRefresh: true,            minimumCountColumns: 2,            columns: [            {                field: 'ORDER_NO',                title: '订单号'            },            {                field: 'BODY_NO',                title: '车身号'            }, {                field: 'VIN',                title: 'VIN码'            }, {                field: 'TM_MODEL_MATERIAL_ID',                title: '整车编码'            },            {                field: 'ORDER_TYPE',                title: '订单类型'            },            {                field: 'ORDER_STATUS',                title: '订单状态'            },            {                field: 'CREATE_DATE',                title: '订单导入时间'            },            {                field: 'PLAN_DATE',                title: '订单计划上线日期'            },            {                field: 'VMS_NO',                title: 'VMS号'            },            {                field: 'ENGIN_CODE',                title: '发动机号'            },            {                field: 'TRANS_CODE',                title: '变速箱号'            },            {                field: 'OFFLINE_DATE_ACT',                title: '实际下线日期'            },            {                field: 'HOLD_RES',                title: 'hold理由'            },            {                field: 'SPC_FLAG',                title: '特殊标记'            },            ],            onLoadSuccess: function (data) {                oTableInit.InitDrop();            }        });    };    oTableInit.InitDrag = function () {        $('#tb_order_left tbody').draggable({            helper: "clone",            start: function (event, ui) {                var old_left_data = JSON.stringify($('#tb_order_left').bootstrapTable("getData"));                var old_right_data = JSON.stringify($('#tb_order_right').bootstrapTable("getData"));                var odata = { index: ++i_statuindex, left_data: old_left_data, right_data: old_right_data };                arrdata.push(odata);            },            stop: function (event, ui) {            }        });    };    oTableInit.InitDrop = function () {        $("#div_tableright div[class=fixed-table-container]").droppable({            drop: function (event, ui) {                var arrtr = $(ui.helper[0]).find("tr[class=selected]");                if (arrtr.length <= 0) {                    alert("请先选中要插单的行");                    return;                }                var oTop = ui.helper[0].offsetTop;                var iRowHeadHeight = 40;                var iRowHeight = 37;                var rowIndex = 0;                if (oTop <= iRowHeadHeight + iRowHeight / 2) {                    rowIndex = 0;                }                else {                    rowIndex = Math.ceil((oTop - iRowHeadHeight) / iRowHeight);                }                for (var i = 0; i < arrtr.length; i++) {                    var arrtd = $(arrtr[i]).find("td");                    var uniqueid = $(arrtr[i]).attr("data-uniqueid");                    var rowdata = {                        ORDER_NO: $(arrtd[1]).text(),                        BODY_NO: $(arrtd[2]).text(),                        VIN: $(arrtd[3]).text(),                        TM_MODEL_MATERIAL_ID: $(arrtd[4]).text(),                        ORDER_TYPE: $(arrtd[5]).text(),                        ORDER_STATUS: $(arrtd[6]).text(),                        CREATE_DATE: $(arrtd[7]).text() == "-" ? null : $(arrtd[7]).text(),                        PLAN_DATE: $(arrtd[8]).text() == "-" ? null : $(arrtd[8]).text(),                        VMS_NO: $(arrtd[9]).text(),                        ENGIN_CODE: $(arrtd[10]).text(),                        TRANS_CODE: $(arrtd[11]).text(),                        OFFLINE_DATE_ACT: $(arrtd[12]).text() == "-" ? null : $(arrtd[12]).text(),                        HOLD_RES: $(arrtd[13]).text(),                        SPC_FLAG: $(arrtd[14]).text(),                        TO_ORDER_ID: uniqueid                    };                    $("#tb_order_right").bootstrapTable("insertRow", { index: rowIndex++, row: rowdata });                    $('#tb_order_left').bootstrapTable("removeByUniqueId", uniqueid);                }                                                oTableInit.InitDrag();            }        });    };    oTableInit.queryParams = function (params) {  //配置参数        var temp = {   //这里的键的名字和控制器的变量名必须一直,这边改动,控制器也需要改成一样的            limit: params.limit,   //页面大小            offset: params.offset,  //页码            strBodyno: $("#txt_search_bodynumber").val(),            strVin: $("#txt_search_vinnumber").val(),            strOrderno: $("#txt_search_ordernumber").val(),            strEngincode: $("#txt_search_engin_code").val(),            strOrderstatus: 0,            strTranscode: $("#txt_search_trans_code").val(),            strVms: $("#txt_search_vms").val(),            strCarcode: $("#txt_search_carcode").val(),            strImportStartdate: $("#txt_search_import_startdate").val(),            strImportEnddate: $("#txt_search_import_enddate").val(),            strSendStartdate: $("#txt_search_send_startdate").val(),            strSendEnddate: $("#txt_search_send_enddate").val(),        };        return temp;    };    oTableInit.queryParamsRight = function (params) {  //配置参数        var temp = {   //这里的键的名字和控制器的变量名必须一直,这边改动,控制器也需要改成一样的            limit: params.limit,   //页面大小            offset: params.offset,  //页码            strBodyno: "",            strVin: "",            strOrderno: "",            strEngincode: "",            strOrderstatus: 5,            strTranscode: "",            strVms: "",            strCarcode: "",            strImportStartdate: "",            strImportEnddate: "",            strSendStartdate: "",            strSendEnddate: "",        };        return temp;    };    return oTableInit;};//页面按钮初始化事件var ButtonInit = function () {    var oInit = new Object();    var postdata = {};    oInit.Init = function () {        //查询点击事件        $("#btn_query").click(function () {            $("#tb_order_left").bootstrapTable('refresh');        });        //重置点击事件        $("#btn_reset").click(function () {            $(".container-fluid").find(".form-control").val("");            $("#tb_order_left").bootstrapTable('refresh');        });        //插单操作点击事件        $("#btn_insertorder").click(function () {                    });        //撤销操作点击事件        $("#btn_cancel").click(function () {            if (i_statuindex <= 0) {                return;            }            for (var i = 0; i < arrdata.length; i++) {                if (arrdata[i].index != i_statuindex) {                    continue;                }                var arr_left_data = eval(arrdata[i].left_data);                var arr_right_data = eval(arrdata[i].right_data);                $('#tb_order_left').bootstrapTable('removeAll');                $('#tb_order_right').bootstrapTable('removeAll');                $('#tb_order_left').bootstrapTable('append', arr_left_data);                for (var x = 0; x < arr_right_data.length; x++) {                    $("#tb_order_right").bootstrapTable("insertRow", { index: x, row: arr_right_data[x] });                }                                //$('#tb_order_right').bootstrapTable('append', arr_right_data);//append之后不能drop                break;            }            i_statuindex--;            //重新注册可拖拽            m_oTable.InitDrag();            //m_oTable.InitDrop();        });    };    return oInit;};
页面整个js代码

还是重点看看部分代码

1、注册左边可拖拽

$('#tb_order_left tbody').draggable({            helper: "clone",            start: function (event, ui) {                var old_left_data = JSON.stringify($('#tb_order_left').bootstrapTable("getData"));                var old_right_data = JSON.stringify($('#tb_order_right').bootstrapTable("getData"));                var odata = { index: ++i_statuindex, left_data: old_left_data, right_data: old_right_data };                arrdata.push(odata);            },            stop: function (event, ui) {            }        });

这里代码很简单,主要做了两件事:

(1)注册tbody的可拖拽,同样适用的JQuery UI的draggable事件。

(2)在开始拖拽前,保存两边表格的数据,用于还原的操作。

2、注册右边drop

    $("#div_tableright div[class=fixed-table-container]").droppable({            drop: function (event, ui) {                var arrtr = $(ui.helper[0]).find("tr[class=selected]");                if (arrtr.length <= 0) {                    alert("请先选中要插单的行");                    return;                }                var oTop = ui.helper[0].offsetTop;                var iRowHeadHeight = 40;                var iRowHeight = 37;                var rowIndex = 0;                if (oTop <= iRowHeadHeight + iRowHeight / 2) {                    rowIndex = 0;                }                else {                    rowIndex = Math.ceil((oTop - iRowHeadHeight) / iRowHeight);                }                for (var i = 0; i < arrtr.length; i++) {                    var arrtd = $(arrtr[i]).find("td");                    var uniqueid = $(arrtr[i]).attr("data-uniqueid");                    var rowdata = {                        ORDER_NO: $(arrtd[1]).text(),                        BODY_NO: $(arrtd[2]).text(),                        VIN: $(arrtd[3]).text(),                        TM_MODEL_MATERIAL_ID: $(arrtd[4]).text(),                        ORDER_TYPE: $(arrtd[5]).text(),                        ORDER_STATUS: $(arrtd[6]).text(),                        CREATE_DATE: $(arrtd[7]).text() == "-" ? null : $(arrtd[7]).text(),                        PLAN_DATE: $(arrtd[8]).text() == "-" ? null : $(arrtd[8]).text(),                        VMS_NO: $(arrtd[9]).text(),                        ENGIN_CODE: $(arrtd[10]).text(),                        TRANS_CODE: $(arrtd[11]).text(),                        OFFLINE_DATE_ACT: $(arrtd[12]).text() == "-" ? null : $(arrtd[12]).text(),                        HOLD_RES: $(arrtd[13]).text(),                        SPC_FLAG: $(arrtd[14]).text(),                        TO_ORDER_ID: uniqueid                    };                    $("#tb_order_right").bootstrapTable("insertRow", { index: rowIndex++, row: rowdata });                    $('#tb_order_left').bootstrapTable("removeByUniqueId", uniqueid);                }                                                oTableInit.InitDrag();            }        });

这里代码和之前有点变化

(1)注册#div_tableright div[class=fixed-table-container]标签的droppable,这个标签是Bootstrap Table表格初始化后自动生成的,为什么不直接注册表格#tb_order_right的droppable,是因为这个标签作用域太小,会导致拖过来的tbody捕捉不到drop事件。而注册表格外部的#div_tableright div[class=fixed-table-container]这个div标签可以解决问题。

(2)通过var arrtr = $(ui.helper[0]).find("tr[class=selected]");找到拖过来tbody里面选中的行,然后将数据取出依次插入右边表格,左边表格则依次删除行数据。

(3)这里有点麻烦的是找drop的位置,我们知道,要想将左边选中的行放到右边指定的位置,那么就得得到当前鼠标drop的位置,这里通过ui.helper[0].offsetTop属性来获得鼠标的Y轴位置,通过计算得到要插入的位置。

3、撤销操作

    $("#btn_cancel").click(function () {            if (i_statuindex <= 0) {                return;            }            for (var i = 0; i < arrdata.length; i++) {                if (arrdata[i].index != i_statuindex) {                    continue;                }                var arr_left_data = eval(arrdata[i].left_data);                var arr_right_data = eval(arrdata[i].right_data);                $('#tb_order_left').bootstrapTable('removeAll');                $('#tb_order_right').bootstrapTable('removeAll');                $('#tb_order_left').bootstrapTable('append', arr_left_data);                for (var x = 0; x < arr_right_data.length; x++) {                    $("#tb_order_right").bootstrapTable("insertRow", { index: x, row: arr_right_data[x] });                }                                //$('#tb_order_right').bootstrapTable('append', arr_right_data);//append之后不能drop                break;            }            i_statuindex--;            //重写注册可拖拽            m_oTable.InitDrag();            //m_oTable.InitDrop();        });

撤销操作和之前也基本相同。

四、总结

效果是完成了,美中不足的是每次拖过去的都是整个tbody,而不是选中的行,奈何多个选中的行无法用某一个容器包起来。暂时没找到合适的解决方案。先这样吧,等以后想到好的方案了再优化吧。

 

五、优化方案(11月6日)

1、注册drap的方法

oTableInit.InitDrag = function () {        $('#tb_order_left tbody').draggable({            helper: "clone",            start: function (event, ui) {                var old_left_data = JSON.stringify($('#tb_order_left').bootstrapTable("getData"));                var old_right_data = JSON.stringify($('#tb_order_right').bootstrapTable("getData"));                var odata = { index: ++i_statuindex, left_data: old_left_data, right_data: old_right_data };                arrdata.push(odata);                $(ui.helper[0]).find("tr[class!=selected]").remove();            },            stop: function (event, ui) {            }        });    };

增加了这一句$(ui.helper[0]).find("tr[class!=selected]").remove();这样在拖动的时候就看不到未选中的行了。

2、精准定位到右边表格指定位置:

oTableInit.InitDrop = function () {        $("#div_tableright div[class=fixed-table-container]").droppable({            drop: function (event, ui) {                var arrtr = $(ui.helper[0]).find("tr[class=selected]");                if (arrtr.length <= 0) {                    toastr.warning('请先选中要插单的行');                    return;                }                var oTop = ui.helper[0].offsetTop;                //因为表格每行的高度可能不一致,所以这里取插入行位置的办法是:取右边表格的行高依次累加,计算行索引。                var rowIndex = 0;                var bIsBottom = true;                var iRowHeadHeight = 40;                var addHeight = iRowHeadHeight;                var trs = $("#tb_order_right tbody tr");                for (var i = 0; i < trs.length; i++) {                    addHeight += $(trs[i]).height();                    if (addHeight > oTop) {                        rowIndex = i;                        bIsBottom = false;//这里参数用来定义拖动到右边表格最下面的情况,这时没有进入到此条件判断里面。                        break;                    }                }                if (bIsBottom) {                    rowIndex = trs.length;                }                for (var i = 0; i < arrtr.length; i++) {                    var arrtd = $(arrtr[i]).find("td");                    var uniqueid = $(arrtr[i]).attr("data-uniqueid");                    var rowdata = {                        ORDER_NO: $(arrtd[1]).text(),                        BODY_NO: $(arrtd[2]).text(),                        VIN: $(arrtd[3]).text(),                        TM_MODEL_MATERIAL_ID: $(arrtd[4]).text(),                        ORDER_TYPE: $(arrtd[5]).text(),                        ORDER_STATUS_NAME: $(arrtd[6]).text(),                        CREATE_DATE: $(arrtd[7]).text() == "-" ? null : $(arrtd[7]).text(),                        PLAN_DATE: $(arrtd[8]).text() == "-" ? null : $(arrtd[8]).text(),                        VMS_NO: $(arrtd[9]).text(),                        ENGIN_CODE: $(arrtd[10]).text(),                        TRANS_CODE: $(arrtd[11]).text(),                        OFFLINE_DATE_ACT: $(arrtd[12]).text() == "-" ? null : $(arrtd[12]).text(),                        HOLD_RES: $(arrtd[13]).text(),                        SPC_FLAG: $(arrtd[14]).text(),                        TO_ORDER_ID: uniqueid,                        ORDER_STATUS:0                    };                    $("#tb_order_right").bootstrapTable("insertRow", { index: rowIndex++, row: rowdata });                    $('#tb_order_left').bootstrapTable("removeByUniqueId", uniqueid);                }                oTableInit.InitDrag();            }        });    };

因为每一行的行高不确定,是由行里面的数据动态撑出来的,所以这里也动态计算drop的位置。

至此,这个小的功能基本告一段落,基本的效果和待优化点也完成了。

转载地址:http://oyttl.baihongyu.com/

你可能感兴趣的文章
圆圈中最后剩下的数字
查看>>
QQ-weiyun(微云)-云储存
查看>>
亚马逊EC2
查看>>
JAVA设计模式之【组合模式】
查看>>
在Ubuntu中部署并测试Fabric 1.0 Beta
查看>>
1月9日云栖精选夜读:场景化封装,一站式使用,普惠AI集成 ——阿里云发布智能媒体管理产品...
查看>>
通过 Visual Studio 的“代码度量值”来改进代码质量
查看>>
Intellij IDEA 使用Spring-boot-devTools无效解决办法
查看>>
知方可补不足~说说吧!timestamp有什么用?
查看>>
[LeetCode] Best Time to Buy and Sell Stock
查看>>
微信公众帐号开发教程第3篇-开发模式启用及接口配置(转)
查看>>
第 12 章 Other Web Server
查看>>
.NET项目web自动化测试实战——Selenium 2.0
查看>>
[LeetCode] Split Concatenated Strings 分割串联字符串
查看>>
Asp.Net SignalR - 持久连接类
查看>>
11.8. NAT
查看>>
PowerShell调用jira rest api实现jira统计自动化
查看>>
Git 时间,将代码托管到GitHub 上
查看>>
火车票秒杀攻略
查看>>
关于Asp.Net中FileUpload控件属性PostedFile.ContentType的提示
查看>>