javascript 拖动表格行实现代码


Posted in Javascript onMay 05, 2011

行拖动的实现思路非常简单,选中一行,往上拖就与上面的行交换位置,往下拖就与下面的行交换位置。问题是如何得到交换行。我见过一个非常详细的教程,它会把表格里的每一行的高度与Y坐标计算出来,换言之,都时是比较e.pageX是否在[rowTop,rowBottom]区间之内。但这也带来第二个问题,有多少行就有多个这样的区间。于是解法就变成取事件源对象,然后再往上取其父对象,如果其父对象是TR元素,就取其[rowTop,rowBottom]区间....思路非常直接,同时也客观做出一个限制——不能使用代理拖动。先不谈是拖动代理还是拖动实物,光是在移动鼠标的过程要做的计算量就非常大,幸好还在IE的承受范围之内。有更好的方法吗?

人之所以先入为主,因为他就握着这么几把锁匙。如果他手上的锁匙非常多时,他在开门时就会稍微停下来,认真挑选了。因此熟悉掌握越多的原生API就越好,我们就才获取更优的选项。换一个思路,在拖动时(mousedown)保存当前行及其样式与坐标,拖动中取得鼠标所在位置上的元素,这个元素是使用一个巧妙的API取得document.elementFromPoint(x,y)。通常情况,我们取得的是TD,当然如果你在里面塞进一个DIV,那就是DIV罗。然后我们再取得其TR元素,然后比较mousedown时保存的TR元素是不是同一个元素,不是同一个元素,我们才做进一步的操作。这时我们就要判其是向上移向下移,简单的减法而已。接着是交换两行,使用insertBefore。最后当mouseup时,还原行的样式就是!由于没有复杂的坐标计算,整个程式出奇的高效!

完整演示代码

<!doctype html>
<html>
 <head>
  <title>表格行拖动</title>
  <script>
     window.onload = function(){
    //绑定事件
    var addEvent = document.addEventListener ? function(el,type,callback){
     el.addEventListener( type, callback, !1 );
    } : function(el,type,callback){
     el.attachEvent( "on" + type, callback );
    }
    //移除事件
    var removeEvent = document.removeEventListener ? function(el,type,callback){
     el.removeEventListener( type, callback );
    } : function(el,type,callback){
     el.detachEvent( "on" + type, callback);
    }
    //精确获取样式
    var getStyle = document.defaultView ? function(el,style){
     return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
    } : function(el,style){
     style = style.replace(/\-(\w)/g, function($, $1){
      return $1.toUpperCase();
     });
     return el.currentStyle[style];
    }
    var dragManager = {
     clientY:0,
     draging:function(e){//mousemove时拖动行
      var dragObj = dragManager.dragObj;
      if(dragObj){
       e = e || event;
       if(window.getSelection){//w3c
        window.getSelection().removeAllRanges();
       }else if(document.selection){
        document.selection.empty();//IE
       }
       var y = e.clientY;
       var down = y > dragManager.clientY;//是否向下移动
       var tr = document.elementFromPoint(e.clientX,e.clientY);
       if(tr && tr.nodeName == "TD"){
        tr = tr.parentNode
        dragManager.clientY = y;
        if( dragObj !== tr){
         tr.parentNode.insertBefore(dragObj, (down ? tr.nextSibling : tr));
        }
       };
      }
     },
     dragStart:function(e){
      e = e || event;
      var target = e.target || e.srcElement;
      if(target.nodeName === "TD"){
       target = target.parentNode;
       dragManager.dragObj = target;
       if(!target.getAttribute("data-background")){
        var background = getStyle(target,"background-color");
        target.setAttribute("data-background",background)
       }
       //显示为可移动的状态
       target.style.backgroundColor = "#ccc";
       target.style.cursor = "move";
       dragManager.clientY = e.clientY;
       addEvent(document,"mousemove",dragManager.draging);
       addEvent(document,"mouseup",dragManager.dragEnd);
      }
     },
     dragEnd:function(e){
      var dragObj = dragManager.dragObj
      if (dragObj) {
       e = e || event;
       var target = e.target || e.srcElement;
       if(target.nodeName === "TD"){
        target = target.parentNode;
        dragObj.style.backgroundColor = dragObj.getAttribute("data-background");
        dragObj.style.cursor = "default";
        dragManager.dragObj = null;
        removeEvent(document,"mousemove",dragManager.draging);
        removeEvent(document,"mouseup",dragManager.dragEnd);
       }
      }
     },
     main:function(el){
      addEvent(el,"mousedown",dragManager.dragStart);
     }
    }
    var el = document.getElementById("table");
    dragManager.main(el);
   }
   
  </script>
  <style>
   .table{
    width:60%;
    border: 1px solid red;
    border-collapse: collapse;
   }
   .table td{
    border: 1px solid red;
    height: 20px;
   }
  </style>
 </head>
 <body>
  <h1>表格行拖动</h1>
  <table id="table" class="table">
   <tbody>
    <tr>
     <td>1</td>
     <td>One</td>
     <td>dom.require</td>
    </tr>
    <tr id="2" >
     <td class="2">2</td>
     <td>Two</td>
     <td>ControlJS </td>
    </tr>
    <tr id="3" >
     <td class="3">3</td>
     <td>Three</td>
     <td>HeadJS</td>
    </tr>
    <tr id="4" >
     <td class="4">4</td>
     <td>Four</td>
     <td>LAB.js</td>
    </tr>
    <tr id="5" >
     <td class="5">5</td>
     <td>Five</td>
     <td>$script.js</td>
    </tr>
    <tr id="6" >
     <td class="6">6</td>
     <td>Six</td>
     <td>NBL.js</td>
    </tr>
   </tbody>
  </table>
 </body>
</html>

核心代码

window.onload = function(){
 //绑定事件
 var addEvent = document.addEventListener ? function(el,type,callback){
  el.addEventListener( type, callback, !1 );
 } : function(el,type,callback){
  el.attachEvent( "on" + type, callback );
 }
 //移除事件
 var removeEvent = document.removeEventListener ? function(el,type,callback){
  el.removeEventListener( type, callback );
 } : function(el,type,callback){
  el.detachEvent( "on" + type, callback);
 }
 //精确获取样式
 var getStyle = document.defaultView ? function(el,style){
  return document.defaultView.getComputedStyle(el, null).getPropertyValue(style)
 } : function(el,style){
  style = style.replace(/\-(\w)/g, function($, $1){
   return $1.toUpperCase();
  });
  return el.currentStyle[style];
 }
 var dragManager = {
  clientY:0,
  draging:function(e){//mousemove时拖动行
   var dragObj = dragManager.dragObj;
   if(dragObj){
    e = e || event;//清除选区
    if(window.getSelection){//w3c
     window.getSelection().removeAllRanges();
    }else if(document.selection){
     document.selection.empty();//IE
    }
    var y = e.clientY;
    var down = y > dragManager.clientY;//是否向下移动
    var tr = document.elementFromPoint(e.clientX,e.clientY);
    if(tr && tr.nodeName == "TD"){
     tr = tr.parentNode
     dragManager.clientY = y;
     if( dragObj !== tr){
      tr.parentNode.insertBefore(dragObj, (down ? tr.nextSibling : tr));
     }
    };
   }
  },
  dragStart:function(e){
   e = e || event;
   var target = e.target || e.srcElement;
   if(target.nodeName === "TD"){
    target = target.parentNode;
    dragManager.dragObj = target;
    if(!target.getAttribute("data-background")){
     var background = getStyle(target,"background-color");
     target.setAttribute("data-background",background)
    }
    //显示为可移动的状态
    target.style.backgroundColor = "#ccc";
    target.style.cursor = "move";
    dragManager.clientY = e.clientY;
    addEvent(document,"mousemove",dragManager.draging);
    addEvent(document,"mouseup",dragManager.dragEnd);
   }
  },
  dragEnd:function(e){
   var dragObj = dragManager.dragObj
   if (dragObj) {
    e = e || event;
    var target = e.target || e.srcElement;
    if(target.nodeName === "TD"){
     target = target.parentNode;
     dragObj.style.backgroundColor = dragObj.getAttribute("data-background");
     dragObj.style.cursor = "default";
     dragManager.dragObj = null;
     removeEvent(document,"mousemove",dragManager.draging);
     removeEvent(document,"mouseup",dragManager.dragEnd);
    }
   }
  },
  main:function(el){
   addEvent(el,"mousedown",dragManager.dragStart);
  }
 }
 var el = document.getElementById("table");
 dragManager.main(el);
}

实现代码二

<!DOCTYPE html> 
<html xmlns="http://www.w3.org/1999/xhtml" > 
<head > 
<title>无标题页</title> 
</head> 
<body> 
<table id="tb1" border="1" cellpadding="3"> 
<tr> 
<th>移动</th> 
<th>数据</th> 
<th>数据</th> 
<th>数据</th> 
</tr> 
<tr> 
<td>*</td> 
<td>11111111111</td> 
<td>sdgergserhserhserh</td> 
<td>awegaw</td> 
</tr> 
<tr> 
<td>*</td> 
<td>222222222</td> 
<td>serherwwwwww</td> 
<td>fafafff</td> 
</tr> 
<tr> 
<td>*</td> 
<td>333333333</td> 
<td>qqqqqqqwewer</td> 
<td>yukyuk</td> 
</tr> 
</table> 
<script type="text/javascript"> 
var curTr = null; 
var tb1 = document.getElementById('tb1'); 
var trs = tb1.getElementsByTagName('tr'); 
tb1.onselectstart = function(){ 
if(curTr){ 
document.selection.empty(); return true; 
} 
}; 
for(var i=1; i<trs.length; i++) { 
var tds = trs[i].getElementsByTagName('td'); 
tds[0].style.cursor = 'move'; 
tds[0].onmousedown = function(){ 
curTr = this.parentNode; 
curTr.style.backgroundColor = '#eff'; 
}; 
tds[0].onmouseover = function() { 
if(curTr && curTr != this.parentNode) { 
this.parentNode.swapNode(curTr); 
} 
} 
} 
document.body.onmouseup = function(){ 
if(curTr){ 
curTr.style.backgroundColor = ''; 
curTr = null; 
} 
}; 
</script> 
</body> 
</html>

注:不兼容firefox,在IE和chrome下测试通过哦。

Javascript 相关文章推荐
情人节专属 纯js脚本1k大小的3D玫瑰效果
Feb 11 Javascript
写得不错的jquery table鼠标经过变色代码
Sep 27 Javascript
js生成动态表格并为每个单元格添加单击事件的方法
Apr 14 Javascript
Node.js 的异步 IO 性能探讨
Oct 08 Javascript
JavaScript字符串对象replace方法实例(用于字符串替换或正则替换)
Oct 16 Javascript
js使用post 方式打开新窗口
Feb 26 Javascript
jQuery实现统计输入文字个数的方法
Mar 11 Javascript
jQuery简单实现验证邮箱格式
Jul 15 Javascript
Vue应用部署到服务器的正确方式
Jul 15 Javascript
Vue和React组件之间的传值方式详解
Jan 31 Javascript
理理Vue细节(推荐)
Apr 16 Javascript
微信小程序iOS下拉白屏晃动问题解决方案
Oct 12 Javascript
小试JQuery的AutoComplete插件
May 04 #Javascript
为你的网站增加亮点的9款jQuery插件推荐
May 03 #Javascript
通过jquery的$.getJSON做一个跨域ajax请求试验
May 03 #Javascript
Jquery 绑定时间实现代码
May 03 #Javascript
jqgrid 简单学习笔记
May 03 #Javascript
用js实现判断当前网址的来路如果不是指定的来路就跳转到指定页面
May 02 #Javascript
jQuery之网页换肤实现代码
Apr 30 #Javascript
You might like
wordpress自定义url参数实现路由功能的代码示例
2013/11/28 PHP
php站内搜索关键词变亮的实现方法
2014/12/30 PHP
Thinkphp实现站点静态化的方法详解
2017/03/21 PHP
PHP实现的二分查找算法实例分析
2017/12/19 PHP
extjs关于treePanel+chekBox全部选中以及清空选中问题探讨
2013/04/02 Javascript
你未必知道的JavaScript和CSS交互的5种方法
2014/04/02 Javascript
详解JavaScript的Polymer框架中的通知交互
2015/07/29 Javascript
Jquery和BigFileUpload实现大文件上传及进度条显示
2016/06/27 Javascript
Vue.js学习笔记之 helloworld
2016/08/14 Javascript
JavaScript trim 实现去除字符串首尾指定字符的简单方法
2016/12/27 Javascript
详解vue mint-ui源码解析之loadmore组件
2017/10/11 Javascript
vue3.0 CLI - 2.6 - 组件的复用入门教程
2018/09/14 Javascript
详解Vue2 添加对scss的支持
2019/01/02 Javascript
详解keep-alive + vuex 让缓存的页面灵活起来
2019/04/19 Javascript
快速解决layui弹窗按enter键不停弹窗的问题
2019/09/18 Javascript
layer弹出层取消遮罩的方法
2019/09/25 Javascript
[01:23]2014DOTA2国际邀请赛 球迷无处不在Ti现场世界杯受关注
2014/07/10 DOTA
[01:11:37]完美世界DOTA2联赛PWL S2 SZ vs FTD.C 第一场 11.19
2020/11/19 DOTA
Python通过命令开启http.server服务器的方法
2017/11/04 Python
python 中if else 语句的作用及示例代码
2018/03/05 Python
Python cookbook(数据结构与算法)对切片命名清除索引的方法
2018/03/13 Python
python和mysql交互操作实例详解【基于pymysql库】
2019/06/04 Python
Python 离线工作环境搭建的方法步骤
2019/07/29 Python
python logging设置level失败的解决方法
2020/02/19 Python
python logging 重复写日志问题解决办法详解
2020/08/04 Python
QT5 Designer 打不开的问题及解决方法
2020/08/20 Python
Python实现邮件发送的详细设置方法(遇到问题)
2021/01/18 Python
乌克兰设计师和品牌的服装:Love&Live
2020/04/14 全球购物
幼儿园托班开学寄语
2014/01/18 职场文书
群众路线教育实践活动整改落实情况汇报
2014/10/28 职场文书
2014年安全保卫工作总结
2014/11/13 职场文书
前台接待岗位职责
2015/02/03 职场文书
PHP控制循环操作的时间
2021/04/01 PHP
MySQL索引知识的一些小妙招总结
2021/05/10 MySQL
Python保存并浏览用户的历史记录
2022/04/29 Python
Zabbix对Kafka topic积压数据监控的问题(bug优化)
2022/07/07 Servers