原生Javascript实现表格行上下拖拽

拖放事件:
拖动元素时,依次触发的事件

  • dragstart 按下鼠标并移动时触发
  • drag 拖动期间持续触发
  • dragend 松开鼠标触发

拖动到有效的放置目标上时,依次触发

  • dragenter 元素被拖到放置目标上
  • dragover 被拖元素在放置目标内移动,持续触发
  • dragleave 元素被拖到放置目标外触发
  • drop 元素被拖到有效的放置目标上(默认无效),并松开鼠标触发

实现代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>table</title>
<style>
  tr,th {
    padding: 30px;
  }
</style>
</head>
<body>
  <table id="myTable" border="1" >
    <thead>
      <tr>
        <th>序列</th>
        <th>名称</th>
        <th>单价</th>
        <th>数量</th>
      </tr>
    </thead>
    <tbody>
      <tr draggable="true">
        <td>1</td>
        <td>冰箱</td>
        <td>13</td>
        <td>14</td>
      </tr>
      <tr draggable="true">
        <td>2</td>
        <td>彩电</td>
        <td>113</td>
        <td>114</td>
      </tr>
      <tr draggable="true">
        <td>3</td>
        <td>空调</td>
        <td>12</td>
        <td>12</td>
      </tr>
      <tr draggable="true">
        <td>4</td>
        <td>洗衣机</td>
        <td>12</td>
        <td>12</td>
      </tr>
    </tbody>
  </table>
  
  <script>
    function drag_row_table() {
      var EventUtil = {  //跨浏览器的事件处理程序,视情况分别选择以下事件处理程序
        addHandler: function(element, type, handler) {
          if(element.addEventListener) {  //DOM2级
            element.addEventListener(type, handler, false);
          }
          else if (element.attachEvent) {  //IE方法
            element.attachEvent('on' + type, handler);
          }
          else {  //DOM1级
            element["on" + type] = handler;
          }
        },
        getTarget: function(event) {  //获取事件的实际目标(在这里是tr),不同于event.currentTarget和this指向的是绑定事件处理程序的目标,(tbody)
          return event.target || event.srcElement;
        },
        preventDefault: function(event) {  //取消事件默认方法
          if(event.preventDefault) {  
            event.preventDefault();
          }
          else {
            event.returnValue = false;  //默认为true,设为falsew为取消默认行为。
          }
        }
      }

      var myTable = document.querySelector('#myTable');
      var tbody = myTable.querySelector("tbody");  //这里监听的是tbody,而不是tr。目的是利用事件冒泡,减少监听的元素个数,提高性能
      var trs = tbody.querySelectorAll("tr");  

      EventUtil.addHandler(tbody, "dragover", function(event) { //默认元素不可放置,这里取消默认,将放置目标修改为可放置的
        EventUtil.preventDefault(event);  
      })

      EventUtil.addHandler(tbody, "dragstart", function(event) {  //监听点击的拖动的元素
      	event.dataTransfer.setData("drag_index", event.target.rowIndex); //将被拖元素的信息,传给放置位置
      })

      EventUtil.addHandler(tbody, "drop", function(event) {  //监听鼠标移动到可放置的放置目标上,松开鼠标的事件
	     EventUtil.preventDefault(event);  //取消在Firefox 3.5+中,放置事件的默认行为是打开被放置目标上的URL
	     let drag_index = parseInt(event.dataTransfer.getData("drag_index"));  //获取传过来的被拖元素的信息
	     let drop_index = EventUtil.getTarget(event).parentNode.rowIndex;  //this为当前触发drop的元素,即放置目标的行下标
	
	     tbody.insertBefore(trs[drag_index], EventUtil.getTarget(event).parentNode.nextSibling);   //将被拖元素放到放置目标的兄弟节点上
	     trs = myTable.querySelectorAll("tr");  //更新变换的tr行信息
      })
    }
    drag_row_table();
  </script>
</body>
</html>

效果:
在这里插入图片描述
这里遇到的坑是,querySelectorAll()方法的底层实现是类似于一组元素的快照,而不是动态查询的(即更新文档结构时,对应的变量也自动更新),为的是避免使用NodeList对象引起的性能问题。因此我们得手动更新querySelectorAll()方法的变量。
符合动态查询的方法有getElementsByTagName()

  • 3
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值