JS コンポーネント Bootstrap Table の複数行ドラッグ効果の実装コード
前書き: 一昨日、JS コンポーネントの Bootstrap テーブルの行ドラッグ効果についての記事を書きました。今日は、前のテーブル行のドラッグに基づいて、選択した複数の行を同時にドラッグできるようにするという新しいニーズを受けました。 。半日かけて調べて効果は出ましたが、物足りなさを感じました。まず共有して、後で最適化するためのより良い方法を考えてください。
1. エフェクト表示
2. ドラッグ中4. ドラッグ前の状態に戻す
2. 要件分析
前の記事を通して、ドラッグ アンド ドロップを実装したい場合は、ドラッグ可能なラベル、つまりコンテナーが必要であることがわかりました。たとえば、前の記事の tr はドラッグ アンド ドロップ コンテナーです。ドラッグする行を選択するとき、ブロガーの最初の反応は、選択した行を div などのコンテナーに配置し、その div をドラッグ可能に登録することですが、実際の状況は tr です。 table.タグで tr を div で囲むと、テーブル内のスタイルが崩れ、インターフェイスが非常に混乱します。明らかに、この道は通れません。そこで、Google Chrome の要素レビューで、Bootstrap テーブルを使用して生成されたテーブル tr の親要素が実際には tbody であることがわかり、tbody のドラッグ アンド ドロップを登録できないかと考えていました。実践により、この方法が実行可能であることが証明されました。それでは始めましょう。3. コード例
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; };
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) { } });
ここでのコードは主に 2 つのことを行います:
(2) ドラッグを開始する前に、復元操作のために両方のテーブルにデータを保存します。
2. 右のドロップを登録します
$("#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] タグの後にこのタグが自動生成されます。ブートストラップ テーブル テーブルが初期化されるのは、ドロップ可能なフォーム #tb_order_right を直接登録しないのはなぜですか? その理由は、このラベルのスコープが小さすぎるため、ドラッグされた tbody がドロップ イベントをキャプチャできないためです。登録フォームの外側にある #div_tableright div[class=fixed-table-container] div タグを使用すると、問題を解決できます。
(2) var arrtr = $(ui.helper[0]).find("tr[class=selected]"); を使用して、tbody にドラッグされた選択された行を検索し、データを取り出して挿入します。それを右側のテーブルと左側のテーブルに分割し、テーブルの行データを 1 つずつ削除します。
(3) ここで少し面倒なのは、左側の選択した行を右側の指定された位置に配置したい場合、ドロップの位置を取得する必要があることです。ここでは、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(); });
元に戻す操作は、基本的には前と同じです。
4. 概要
効果は完了です。唯一の欠点は、選択した行ではなくボディ全体をドラッグするたびに、選択した複数の行をコンテナー内にラップできないことです。適切な解決策はまだ見つかっていません。とりあえずこれを実行して、後で良い解決策が見つかったら最適化しましょう。 5. 最適化計画1. drapoTableInit.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) { } }); };
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(); } }); };
この時点で、この小さな機能は基本的に終了し、基本的な効果と最適化するポイントも完成しました。
その他の JS コンポーネント、Bootstrap Table、複数行ドラッグ効果の実装コード関連記事については、PHP 中国語 Web サイトに注目してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









記事では、JavaScriptライブラリの作成、公開、および維持について説明し、計画、開発、テスト、ドキュメント、およびプロモーション戦略に焦点を当てています。

この記事では、ブラウザでJavaScriptのパフォーマンスを最適化するための戦略について説明し、実行時間の短縮、ページの負荷速度への影響を最小限に抑えることに焦点を当てています。

フロントエンドのサーマルペーパーチケット印刷のためのよくある質問とソリューションフロントエンド開発におけるチケット印刷は、一般的な要件です。しかし、多くの開発者が実装しています...

この記事では、ブラウザ開発者ツールを使用した効果的なJavaScriptデバッグについて説明し、ブレークポイントの設定、コンソールの使用、パフォーマンスの分析に焦点を当てています。

スキルや業界のニーズに応じて、PythonおよびJavaScript開発者には絶対的な給与はありません。 1. Pythonは、データサイエンスと機械学習でさらに支払われる場合があります。 2。JavaScriptは、フロントエンドとフルスタックの開発に大きな需要があり、その給与もかなりです。 3。影響要因には、経験、地理的位置、会社の規模、特定のスキルが含まれます。

この記事では、ソースマップを使用して、元のコードにマッピングすることにより、Minified JavaScriptをデバッグする方法について説明します。ソースマップの有効化、ブレークポイントの設定、Chrome DevtoolsやWebpackなどのツールの使用について説明します。

同じIDを持つ配列要素をJavaScriptの1つのオブジェクトにマージする方法は?データを処理するとき、私たちはしばしば同じIDを持つ必要性に遭遇します...

Console.log出力の違いの根本原因に関する詳細な議論。この記事では、Console.log関数の出力結果の違いをコードの一部で分析し、その背後にある理由を説明します。 �...
