• 技术文章 >web前端 >js教程

    JS组件Bootstrap Table表格行拖拽效果实现代码

    高洛峰高洛峰2017-03-20 14:02:16原创1146
    一、业务需求及实现效果

    项目涉及到订单模块,那天突然接到一个需求,说是两种不同状态的订单之间要实现插单的效果,页面上呈现方式是:左右两个Table,左边Table里面是状态为1的订单,右边Table里面是状态为2订单,左边Table里面的行数据拖动到右边Table里面指定行的位置,拖动完成后,左边表格减少一行,右边表格增加一行。除此之外,还需要撤销操作(相当于Ctrl + Z操作),能够返回到上一步的状态。可能描述会让大家模拟两可,反正已经实现了,先来看看效果图吧。

    1、先看看拖动之前的效果

    2、这是拖动左边表格行数据的效果

    JS组件Bootstrap Table表格行拖拽效果实现代码

    大前端零基础入门到就业:进入学习

    3、拖动一行完成之后表格数据的效果

    JS组件Bootstrap Table表格行拖拽效果实现代码

    4、第二次、第三次拖动完成后效果

    JS组件Bootstrap Table表格行拖拽效果实现代码

    5、右边表格上面撤销操作点击效果

    JS组件Bootstrap Table表格行拖拽效果实现代码

    6、多次点击撤销,表格回到初始状态

    JS组件Bootstrap Table表格行拖拽效果实现代码

    二、代码示例
    接到需求的第一感觉是应该上Bootstrap table api里面找一下,毕竟开源的力量是强大的,或许有相关的示例呢。经过一番查找,很可惜,Bootstrap Table没有这种两张表格之间的操作。想想其实也可以理解,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>

    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>');
     $("#p_more_search").collapse('hide');
     }
     else {
     $(this).html('收起<label class="glyphicon glyphicon-menu-up"></label>');
     $("#p_more_search").collapse('show')
     }
     });
     };
     
     return oInit;
    };

    我们重点来看几个地方的代码:
    2.2.1 左边表格加载成功之后执行表格行的可拖拽。

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

    $("#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事件时,取到当前拖过来的行数据,计算当前鼠标所在的位置,在右边表格指定位置插入拖过来的行数据。然后删除左边表格拖过来的行数据。
    2.2.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();
     });

    撤销操作主要是通过全局变量arrdata里面的索引判断撤销到哪一步,然后根据索引取出当前步骤的左右表格数据,依次向两表格插入数据,然后i_statuindex依次递减,直至等于零,由于左边表格行数据全部重写加载过,所以需要重新注册可拖拽事件。就是这么简单的三步就能实现想要的效果,是不是很简单~~

    以上就是本文的全部内容,希望对大家的学习有所帮助。

    更多JS组件Bootstrap Table表格行拖拽效果实现代码相关文章请关注PHP中文网!

    相关文章:

    详解Bootstrap实现基本布局的方法

    BootStrap table使用方法分析

    使用Bootstrap过渡效果Transition模态框(Modal)的方法

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。

    前端(VUE)零基础到就业课程:点击学习

    清晰的学习路线+老师随时辅导答疑

    自己动手写 PHP MVC 框架:点击学习

    快速了解MVC架构、了解框架底层运行原理

    上一篇:JS组件Bootstrap Table表格多行拖拽效果实现代码 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• 浅析Angular中的Change Detection机制• 浅析Angular变更检测中的订阅异步事件• 一文聊聊node中的path模块• 一文带你深入了解Node中的Buffer类• Angular学习之聊聊Http ( 错误处理 / 请求拦截 )
    1/1

    PHP中文网