1. ビジネス要件と実装効果
このプロジェクトには、注文モジュールが含まれており、その日突然、注文を挿入したときの効果を、ステータスの異なる 2 つの注文の間で達成する必要があるという要件を受け取りました。左側のテーブルと右側のテーブルです。左側のテーブルにはステータス 1 の注文が含まれ、右側のテーブルにはステータス 2 の注文が含まれています。 ドラッグが完了したら、左側のテーブルの行データを右側のテーブルの指定された行位置にドラッグします。左側のテーブルは 1 行削減され、右側のテーブルは 1 行削減されます。テーブルに行を追加します。さらに、前のステップに戻るには、操作を元に戻す (Ctrl + Z 操作に相当) 必要もあります。この説明を読むと、シミュレーションについて考え直してしまうかもしれません。とにかく、最初にレンダリングを見てみましょう。
1. まず、ドラッグ前の効果を見てください
2. これは、左側のテーブル行データをドラッグした場合の効果です
3. 行をドラッグした後のテーブルデータの効果です。 4. 2回目、3回目のドラッグが完了した後の効果
5. 右側のテーブルの「元に戻す」操作をクリックした場合の効果
6. 「元に戻す」を複数回クリックすると、テーブルが初期状態に戻ります
2. コード例リクエストを受け取ったときに最初に思ったのは、Bootstrap テーブル API で探すべきだということです。結局のところ、オープンソースの力は強力であり、あるかもしれません。関連する例。少し調べてみましたが、残念ながら、Bootstrap Table には 2 つのテーブル間でそのような操作はありません。実際に考えてみると、Bootstrap Table は特定の動的テーブルのデータ バインディングを目的として設計されていることがわかります。たとえば、ドラッグ アンド ドロップによる並べ替えのための優れたソリューションがあります。テーブル内の行の Reorder Rows) は、ブロガーのような特別なニーズを自分で実現する必要があるようです。
1. 要件の分析 さて、自分で書くことにしたので、要件の分析を始めました。ドラッグ アンド ドロップの効果に関して言えば、この操作のより難しい部分であるようです。 JsPlumb を使用すると多用されることが判明したため、JQuery UI の魔法の draggable.js とdroppable.js を考えました。ドラッグ アンド ドロップの問題は解決しましたが、操作を元に戻した場合はどうすればよいかという問題がまだ残っています。 Ctrl+Z は復元を意味します。復元とは何ですか?前のステップの操作に戻るため、前のステップの状態を保存できることが前提となります。あるステップの状態を保存する方法については、グローバル変数を使用する必要があります。 Json が必要です。これはそれぞれ、現在のステップのインデックス、左側のテーブルのデータ、右側のテーブルのデータです。それほど難しくないようなので、始めてみましょう。 2. コード例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> @{ 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> <p class="panel-body" style="padding-bottom:0px;"> <p class="panel panel-default" style="margin-bottom:0px;"> <p class="panel-heading">查询条件</p> <p class="panel-body container-fluid"> <p class="row"> <p 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> </p> <p 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> </p> <p 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> </p> <p 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> </p> </p> <p class="collapse" id="p_more_search"> <p class="row" style="margin-top:15px;"> <p 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> </p> <p 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> </p> <p 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> </p> <p 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> </p> </p> <p class="row" style="margin-top:15px;"> <p 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> </p> <p 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> </p> <p 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> </p> </p> </p> <p class="row" style="float:right;margin-right:50px;margin-top:13px;"> <p> <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> </p> </p> </p> </p> <p class="collapse_p_outside"> <p class="collapse_p_inside"></p> <span id="span_collapse" href="#p_more_search" class="collapse_p_inside_ele">展开<label class="glyphicon glyphicon-menu-down"></label></span> </p> </p> @*<p id="toolbar_left" class="btn-group"> </p>*@ <p 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> </p> <p class="panel-body" style="padding-top:0px;"> <p id="p_tableleft" class="col-md-6"> <table id="tb_order_left"></table> </p> <p id="p_tableright" class="col-md-6"> <table id="tb_order_right"></table> </p> </p>
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>'); $("#p_more_search").collapse('hide'); } else { $(this).html('收起<label class="glyphicon glyphicon-menu-up"></label>'); $("#p_more_search").collapse('show') } }); }; return oInit; };
$('#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) { } });
ドラッグ可能の開始イベントでは、arrdata 変数にドラッグする前に、左右のテーブルのすべてのデータを保存します。グローバル変数 i_statuindex は、現在のステップのインデックスを記録するために使用され、操作を元に戻すために使用されます。
2.2.2 右側のテーブルが正常にロードされたら、テーブルのドロップ可能イベントを登録します$("#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(); } });
//撤销操作点击事件 $("#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(); });
上記がこの記事の全内容です。皆さんの学習に役立つことを願っています。
Bootstrapによる基本レイアウトの実装方法を詳しく解説