JS組件系列——Bootstrap Table 表格行拖拽

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

前言:以前一直在研究DDD相關知識,很久沒更新JS系列文章了。這兩天作了一個簡單的業務需求,以爲效果還能夠,今天在這裏分享給你們,歡迎拍磚~~css

1、業務需求及實現效果

項目涉及到訂單模塊,那天忽然接到一個需求,說是兩種不一樣狀態的訂單之間要實現插單的效果,頁面上呈現方式是:左右兩個Table,左邊Table裏面是狀態爲1的訂單,右邊Table裏面是狀態爲2訂單,左邊Table裏面的行數據拖動到右邊Table裏面指定行的位置,拖動完成後,左邊表格減小一行,右邊表格增長一行。除此以外,還須要撤銷操做(至關於Ctrl + Z操做),可以返回到上一步的狀態。可能描述會讓你們模擬兩可,反正已經實現了,先來看看效果圖吧。html

一、先看看拖動以前的效果

二、這是拖動左邊表格行數據的效果

三、拖動一行完成以後表格數據的效果

四、第二次、第三次拖動完成後效果

五、右邊表格上面撤銷操做點擊效果

六、屢次點擊撤銷,表格回到初始狀態

2、代碼示例

初初接到需求,博主的第一感受是應該上Bootstrap table api裏面找一下,畢竟開源的力量是強大的,或許有相關的示例呢。通過一番查找,很惋惜,Bootstrap Table沒有這種兩張表格之間的操做。想一想其實也能夠理解,Bootstrap Table是針對某個動態表格數據綁定的,它的側重點是表格內部的功能,好比表格內部行的拖拽排序(Reorder Rows)有很好的解決方案,對於像博主這樣的特殊需求,彷佛也應該本身去實現。jquery

一、需求分析

既然決定本身去寫,博主開始分析需求,彷佛這個操做裏面比較困難的是拖拽效果,說到拖拽效果,原來使用JsPlumb的時候那使用太多了,因而就想到了咱們神奇的JQuery UI裏面的draggable.js 和droppable.js。拖拽的問題解決了,那麼還有一個難點,就是撤銷操做怎麼辦?咱們知道Ctrl+z的意思是還原,什麼叫還原?就是返回到上一步的操做,那麼前提是要可以保存上一步的狀態,說到保存某一步的狀態,博主就知道怎麼作了,須要一個全局變量Json,裏面要有三個鍵值對,分別是當前步驟的索引、左邊表格的數據、右邊表格的數據。彷佛也不太難嘛,博主就此着手,開幹。ajax

二、代碼示例

 2.1 cshtml頁面代碼

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    @Styles.Render("~/Content/css")
    @Styles.Render("~/Content/table-css")
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/knockout")
    @Scripts.Render("~/bundles/bootstrap")
    @Scripts.Render("~/bundles/bootstrap-table")
    @RenderSection("Scripts", false)
</head>
<body>
    @RenderBody()
</body>
</html>
母版_layout.cshtml
@{
    ViewBag.Title = "訂單插單";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

@Scripts.Render("~/bundles/Order/InsertOrder")
@Styles.Render("~/bundles/Order/css")
@Scripts.Render("~/Content/bootstrap/datepicker/js")
@Styles.Render("~/Content/bootstrap/datepicker/css")

<script src="~/Content/jquery-ui-1.11.4.custom/jquery-ui.min.js"></script>

<div class="panel-body" style="padding-bottom:0px;">
    
        <div class="panel panel-default" style="margin-bottom:0px;">
            <div class="panel-heading">查詢條件</div>
            <div class="panel-body container-fluid">
                <div class="row">
                    <div class="col-md-3">
                        <label for="txt_search_ordernumber" class="col-sm-4 control-label" style="margin-top:6px;">訂單號</label>
                        <span class="col-sm-8">
                            <input type="text" class="form-control" id="txt_search_ordernumber">
                        </span>
                    </div>
                    <div class="col-md-3">
                        <label for="txt_search_bodynumber" class="col-sm-3 control-label" style="margin-top:6px;">車身號</label>
                        <span class="col-sm-8">
                            <input type="text" class="form-control" id="txt_search_bodynumber">
                        </span>
                    </div>
                    <div class="col-md-3">
                        <label for="txt_search_vinnumber" class="col-sm-4 control-label" style="margin-top:6px;">VIN碼</label>
                        <span class="col-sm-8">
                            <input type="text" class="form-control" id="txt_search_vinnumber">
                        </span>
                    </div>
                    <div class="col-md-3">
                        <label for="txt_search_engin_code" class="col-sm-4 control-label" style="margin-top:6px;">發動機號</label>
                        <span class="col-sm-8">
                            <input type="text" class="form-control" id="txt_search_engin_code">
                        </span>
                    </div>
                </div>
                <div class="collapse" id="div_more_search">
                    <div class="row" style="margin-top:15px;">
                        <div class="col-md-3">
                            <label for="txt_search_import_startdate" class="col-sm-4 control-label" style="margin-top:6px;">導入時間</label>
                            <span class="col-sm-8">
                                <input type="text" class="form-control datetimepicker" readonly id="txt_search_import_startdate">
                            </span>
                        </div>
                        <div class="col-md-3">
                            <label for="txt_search_import_enddate" class="col-sm-3 control-label" style="margin-top:6px;"></label>
                            <span class="col-sm-8">
                                <input type="text" class="form-control datetimepicker" readonly id="txt_search_import_enddate">
                            </span>
                        </div>
                        <div class="col-md-3">
                            <label for="txt_search_send_startdate" class="col-sm-4 control-label" style="margin-top:6px;">下發時間</label>
                            <span class="col-sm-8">
                                <input type="text" class="form-control datetimepicker" readonly id="txt_search_send_startdate">
                            </span>
                        </div>
                        <div class="col-md-3">
                            <label for="txt_search_send_enddate" class="col-sm-4 control-label" style="margin-top:6px;"></label>
                            <span class="col-sm-8">
                                <input type="text" class="form-control datetimepicker" readonly id="txt_search_send_enddate">
                            </span>
                        </div>
                    </div>

                    <div class="row" style="margin-top:15px;">
                        <div class="col-md-3">
                            <label for="txt_search_carcode" class="col-sm-4 control-label" style="margin-top:6px;">整車編碼</label>
                            <span class="col-sm-8">
                                <input type="text" class="form-control" id="txt_search_carcode">
                            </span>
                        </div>
                        <div class="col-md-3">
                            <label for="txt_search_vms" class="col-sm-3 control-label" style="margin-top:6px;">VMS號</label>
                            <span class="col-sm-8">
                                <input type="text" class="form-control" id="txt_search_vms">
                            </span>
                        </div>
                        <div class="col-md-3">
                            <label for="txt_search_trans_code" class="col-sm-4 control-label" style="margin-top:6px;">變速箱號</label>
                            <span class="col-sm-8">
                                <input type="text" class="form-control" id="txt_search_trans_code">
                            </span>
                        </div>
                    </div>
                </div>

                    <div class="row" style="float:right;margin-right:50px;margin-top:13px;">
                        <div>
                            <button type="button" id="btn_query" class="btn btn-primary" style="margin-right:20px;width:100px;">查詢</button>
                            <button type="submit" id="btn_reset" class="btn btn-default" style="margin-right:20px;width:100px;">重置</button>
                        </div>

                    </div>
                </div>
        </div>

    <div class="collapse_div_outside">
        <div class="collapse_div_inside"></div>
        <span id="span_collapse" href="#div_more_search" class="collapse_div_inside_ele">展開<label class="glyphicon glyphicon-menu-down"></label></span>
    </div>
</div>

@*<div id="toolbar_left" class="btn-group">
</div>*@
<div id="toolbar_right" class="btn-group">
    <button id="btn_cancel" type="button" class="btn btn-default">
        <span class="glyphicon glyphicon-backward aria-hidden="true"></span>撤銷
    </button>
    <button id="btn_insertorder" type="button" class="btn btn-default">
        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>插單
    </button>
</div>
<div class="panel-body" style="padding-top:0px;">
    <div id="div_tableleft" class="col-md-6">
        <table id="tb_order_left"></table>
    </div>
    <div id="div_tableright" class="col-md-6">
        <table id="tb_order_right"></table>
    </div>
</div>
訂單插單頁面.cshtml

 2.2 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();
            }
        });
     //初始化右邊表格
        $('#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();
            }
        });
    };
    //註冊表格行的draggable事件
    oTableInit.InitDrag = function () {
        $('#tb_order_left tr').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) {
                
            }
        });
    };
    //註冊右邊表格的droppable事件
    oTableInit.InitDrop = function () {
        $("#tb_order_right").droppable({
            drop: function (event, ui) {
                var arrtd = $(ui.helper[0]).find("td");
                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: $(ui.helper[0]).attr("data-uniqueid")

                };
                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);
                }
          //插入右邊表格指定位置行數據
                $("#tb_order_right").bootstrapTable("insertRow", { index: rowIndex, row: rowdata });
                $('#tb_order_left').bootstrapTable("removeByUniqueId", $(ui.helper[0]).attr("data-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_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();
        });

        //搜索欄展開收起點擊事件
        $("#span_collapse").click(function () {
            if ($(this).text() == "收起") {
                $(this).html('展開<label class="glyphicon glyphicon-menu-down"></label>');
                $("#div_more_search").collapse('hide');
            }
            else {
                $(this).html('收起<label class="glyphicon glyphicon-menu-up"></label>');
                $("#div_more_search").collapse('show')
            }
        });
    };

    return oInit;
};
所有JS代碼

 咱們重點來看幾個地方的代碼:bootstrap

2.2.1  左邊表格加載成功以後執行表格行的可拖拽。api

$('#tb_order_left tr').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) {
            }
        });

在draggable的start事件中,咱們將拖拽以前的左右表格中的數據所有保存到arrdata變量中,i_statuindex這個全局變量用於記錄當前這一步的索引,用於撤銷操做。數組

 

2.2.2 右邊表格在加載成功以後註冊表格的droppable事件app

    $("#tb_order_right").droppable({
            drop: function (event, ui) {
                var arrtd = $(ui.helper[0]).find("td");
                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: $(ui.helper[0]).attr("data-uniqueid")

                };
                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);
                }
                $("#tb_order_right").bootstrapTable("insertRow", { index: rowIndex, row: rowdata });
                $('#tb_order_left').bootstrapTable("removeByUniqueId", $(ui.helper[0]).attr("data-uniqueid"));
                oTableInit.InitDrag();
            }
        });

在drop事件時,取到當前拖過來的行數據,計算當前鼠標所在的位置,在右邊表格指定位置插入拖過來的行數據。而後刪除左邊表格拖過來的行數據。ide

 

2.2.3 撤銷操做代碼post

     //撤銷操做點擊事件
        $("#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();
        });

撤銷操做主要是經過全局變量arrdata裏面的索引判斷撤銷到哪一步,而後根據索引取出當前步驟的左右表格數據,依次向兩表格插入數據,而後i_statuindex依次遞減,直至等於零,因爲左邊表格行數據所有重寫加載過,因此須要從新註冊可拖拽事件。就是這麼簡單的三步就能實現想要的效果,是否是很簡單~~

相關文章
相關標籤/搜索