JS組件系列——Bootstrap Table 表格行拖拽(二:多行拖拽)

原文: JS組件系列——Bootstrap Table 表格行拖拽(二:多行拖拽)

前言:前天剛寫了篇JS組件系列——Bootstrap Table 表格行拖拽,今天接到新的須要,須要在以前表格行拖拽的基礎上可以同時拖拽選中的多行。博主用了半天時間研究了下,效果是出來了,可是感受不盡如人意。先把它分享出來,之後想到更好的辦法再優化吧。html

1、效果展現

一、拖動前

 

二、拖動中

三、拖動後

四、撤銷回到拖動前狀態

 

2、需求分析

經過上篇咱們知道,若是要實現拖拽,必需要有一個能夠拖拽的標籤,或者叫容器,好比上篇裏面的tr就是一個拖拽的容器,那麼若是要實現選擇行的拖拽,那麼博主的第一反應是將選中的行放到一個容器裏面,好比放到一個div中,而後註冊這個div的可拖拽,但是實際狀況是,tr是在table裏面的標籤,若是將tr用div包起來,勢必將table裏面的樣式打亂,這個界面就真的是亂掉了。很顯然,這條路走不通。而後經過谷歌瀏覽器審覈元素知道,用Bootstrap table生成的表格tr的父級元素其實是tbody,因而在想是否能夠註冊tbody的拖拽,實踐證實,此法可行。因而就此開幹。ajax

3、代碼示例

cshtm的代碼就再也不重複,和上篇相同。咱們重點來看看js代碼。bootstrap

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代碼

仍是重點看看部分代碼api

一、註冊左邊可拖拽

$('#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事件。app

(2)在開始拖拽前,保存兩邊表格的數據,用於還原的操做。ide

二、註冊右邊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();
            }
        });

這裏代碼和以前有點變化post

(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裏面選中的行,而後將數據取出依次插入右邊表格,左邊表格則依次刪除行數據。ui

(3)這裏有點麻煩的是找drop的位置,咱們知道,要想將左邊選中的行放到右邊指定的位置,那麼就得獲得當前鼠標drop的位置,這裏經過ui.helper[0].offsetTop屬性來得到鼠標的Y軸位置,經過計算獲得要插入的位置。

三、撤銷操做

    $("#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();
        });

撤銷操做和以前也基本相同。

4、總結

效果是完成了,美中不足的是每次拖過去的都是整個tbody,而不是選中的行,奈何多個選中的行沒法用某一個容器包起來。暫時沒找到合適的解決方案。先這樣吧,等之後想到好的方案了再優化吧。

 

5、優化方案(11月6日)

一、註冊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();這樣在拖動的時候就看不到未選中的行了。

二、精準定位到右邊表格指定位置:

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的位置。

至此,這個小的功能基本告一段落,基本的效果和待優化點也完成了。

源碼下載

相關文章
相關標籤/搜索