Home > Article > Web Front-end > JS component Bootstrap Table table row drag effect implementation code_javascript skills
1. Business needs and implementation results
The project involves the order module. I suddenly received a requirement that day, saying that the order insertion effect should be achieved between two orders with different statuses. The presentation method on the page is: two tables on the left and right, and the status in the table on the left is For the order 1, there is an order with status 2 in the right table. Drag the row data in the left table to the specified row position in the right table. After the drag is completed, the left table decreases by one row and the right table increases by one row. In addition, you also need to undo the operation (equivalent to the Ctrl Z operation) to return to the previous step. Maybe the description will make you think twice about simulating it. Anyway, it has been implemented. Let’s take a look at the renderings first.
1. First look at the effect before dragging
2. This is the effect of dragging the table row data on the left
3. The effect of table data after dragging a row
4. The effect after the second and third dragging is completed
5. The effect of clicking the undo operation on the right table
6. Click Undo multiple times to return the form to its initial state
2. Code examples
The first thing I thought when I received the request was that I should search in the Bootstrap table api. After all, the power of open source is powerful, and there may be relevant examples. After some searching, unfortunately, Bootstrap Table does not have such an operation between two tables. If you think about it, you can actually understand that Bootstrap Table is designed for data binding of a certain dynamic table. Its focus is on the functions inside the table. For example, there is a good solution for drag-and-drop sorting (Reorder Rows) of rows inside the table. It seems that special needs like bloggers should be realized by themselves.
1. Demand analysis
Now that I decided to write it myself, I started to analyze the requirements. It seems that the more difficult part of this operation is the drag and drop effect. When it comes to the drag and drop effect, it turns out that when using JsPlumb, it uses too much, so I thought of the drag and drop effect in our magical JQuery UI. draggable.js and droppable.js. Now that the drag and drop problem is solved, there is still another difficulty, which is what to do if you undo the operation? We know that Ctrl z means restore. What is restore? It is to return to the operation of the previous step, so the premise is to be able to save the state of the previous step. When it comes to saving the state of a certain step, bloggers know how to do it. A global variable Json is needed, which must have three key-value pairs, respectively. It is the index of the current step, the data of the table on the left, and the data of the table on the right. It doesn't seem too difficult, so let's get started.
2. Code example
2.1 cshtml page code
<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> @{ 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>
2.2 js code
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; };
Let’s focus on the code in several places:
2.2.1 After the table on the left is loaded successfully, the table rows can be dragged and dropped.
$('#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) { } });
In the start event of draggable, we save all the data in the left and right tables before dragging to the arrdata variable. The global variable i_statuindex is used to record the index of the current step and is used to undo the operation.
2.2.2 After the table on the right is loaded successfully, register the droppable event of the form
$("#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(); } });
In the drop event, get the currently dragged row data, calculate the current mouse position, and insert the dragged row data at the specified position in the table on the right. Then delete the row data dragged over from the left table.
2.2.3 Undo operation code
//撤销操作点击事件 $("#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依次遞減,直至等於零,由於左邊表格行資料全部重寫載入過,所以需要重新註冊可拖曳事件。就是這麼簡單的三步驟就能實現想要的效果,是不是很簡單~~
以上就是本文的全部內容,希望對大家的學習有所幫助。