之前写过一篇可拖动的DIV讲如何实现可拖动的元素,最后提出了几点不足,这篇文章主要就是回答着三个问题

1. 浏览器兼容性

2. 边界检查

3. 拖动卡顿、失灵

先附上上次代码

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Test</title>
  5. <style type="text/css" >
  6. html,body
  7. {
  8. height:100%;
  9. width:100%;
  10. padding:0;
  11. margin:0;
  12. }
  13.  
  14. .dialog
  15. {
  16. width:250px;
  17. height:250px;
  18. position:absolute;
  19. background-color:#ccc;
  20. -webkit-box-shadow:1px 1px 3px #292929;
  21. -moz-box-shadow:1px 1px 3px #292929;
  22. box-shadow:1px 1px 3px #292929;
  23. margin:10px;
  24. }
  25.  
  26. .dialog-title
  27. {
  28. color:#fff;
  29. background-color:#404040;
  30. font-size:12pt;
  31. font-weight:bold;
  32. padding:4px 6px;
  33. cursor:move;
  34. }
  35.  
  36. .dialog-content
  37. {
  38. padding:4px;
  39. }
  40. </style>
  41. </head>
  42. <body>
  43. <div id="dlgTest" class="dialog">
  44. <div class="dialog-title">Dialog</div>
  45. <div class="dialog-content">
  46. This is a draggable test.
  47. </div>
  48. </div>
  49. <script type="text/javascript">
  50. var Dragging=function(validateHandler){ //参数为验证点击区域是否为可移动区域,如果是返回欲移动元素,负责返回null
  51. var draggingObj=null; //dragging Dialog
  52. var diffX=0;
  53. var diffY=0;
  54.  
  55. function mouseHandler(e){
  56. switch(e.type){
  57. case 'mousedown':
  58. draggingObj=validateHandler(e);//验证是否为可点击移动区域
  59. if(draggingObj!=null){
  60. diffX=e.clientX-draggingObj.offsetLeft;
  61. diffY=e.clientY-draggingObj.offsetTop;
  62. }
  63. break;
  64.  
  65. case 'mousemove':
  66. if(draggingObj){
  67. draggingObj.style.left=(e.clientX-diffX)+'px';
  68. draggingObj.style.top=(e.clientY-diffY)+'px';
  69. }
  70. break;
  71.  
  72. case 'mouseup':
  73. draggingObj =null;
  74. diffX=0;
  75. diffY=0;
  76. break;
  77. }
  78. };
  79.  
  80. return {
  81. enable:function(){
  82. document.addEventListener('mousedown',mouseHandler);
  83. document.addEventListener('mousemove',mouseHandler);
  84. document.addEventListener('mouseup',mouseHandler);
  85. },
  86. disable:function(){
  87. document.removeEventListener('mousedown',mouseHandler);
  88. document.removeEventListener('mousemove',mouseHandler);
  89. document.removeEventListener('mouseup',mouseHandler);
  90. }
  91. }
  92. }
  93.  
  94. function getDraggingDialog(e){
  95. var target=e.target;
  96. while(target && target.className.indexOf('dialog-title')==-1){
  97. target=target.offsetParent;
  98. }
  99. if(target!=null){
  100. return target.offsetParent;
  101. }else{
  102. return null;
  103. }
  104. }
  105.  
  106. Dragging(getDraggingDialog).enable();
  107. </script>
  108. </body>
  109. </html>

浏览器兼容性

这个是最好解决的问题了,看看上面代码涉及到浏览器兼容性的地方无非就是event获取及事件源获取、事件绑定,为此特意写两个函数来做此事。

  1. function addEvent(element, type, key, handler) {//绑定事件处理程序
  2. if (element[type + key])
  3. return false;
  4. if (typeof element.addEventListener != "undefined") {
  5. element[type + key] = handler;
  6. element.addEventListener(type, handler, false);
  7. }
  8. else {
  9. element['e' + type + key] = handler;
  10. element[type + key] = function () {
  11. element['e' + type + key](window.event); //解决IE浏览器event及this问题
  12. };
  13. element.attachEvent('on' + type, element[type + key]);
  14. }
  15. return true;
  16. }
  17.  
  18. function removeEvent(element, type, key) {//移除事件
  19. if (!element[type + key])
  20. return false;
  21.  
  22. if (typeof element.removeEventListener != "undefined") {
  23. element.removeEventListener(type, element[type + key], false);
  24. }
  25. else {
  26. element.detachEvent("on" + type, element[type + key]);
  27. element['e' + type + key] = null;
  28. }
  29.  
  30. element[type + key] = null;
  31. return true;
  32. }

使用这两个函数用于添加和移除事件,就可以解决浏览器兼容性问题,有兴趣的同学可以研究一下,这是根据jQuery作者John Resig写法的改版,参数key是绑定函数的自定义唯一标识,用于removeEvent时取消绑定,改版后代码是这样

  1. var Dragging = function (validateHandler) { //参数为验证点击区域是否为可移动区域,如果是返回欲移动元素,负责返回null
  2. var draggingObj = null; //dragging Dialog
  3. var diffX = 0;
  4. var diffY = 0;
  5.  
  6. function mouseHandler(e) {
  7. switch (e.type) {
  8. case 'mousedown':
  9. draggingObj = validateHandler(e);//验证是否为可点击移动区域
  10. if (draggingObj != null) {
  11. diffX = e.clientX - draggingObj.offsetLeft;
  12. diffY = e.clientY - draggingObj.offsetTop;
  13. }
  14. break;
  15.  
  16. case 'mousemove':
  17. if (draggingObj) {
  18. draggingObj.style.left = (e.clientX - diffX) + 'px';
  19. draggingObj.style.top = (e.clientY - diffY) + 'px';
  20. }
  21. break;
  22.  
  23. case 'mouseup':
  24. draggingObj = null;
  25. diffX = 0;
  26. diffY = 0;
  27. break;
  28. }
  29. };
  30.  
  31. return {
  32. enable: function () {
  33. addEvent(document, 'mousedown', 'drag-down', mouseHandler);
  34. addEvent(document, 'mousemove', 'drag-move', mouseHandler);
  35. addEvent(document, 'mouseup', 'drag-up', mouseHandler);
  36. },
  37. disable: function () {
  38. removeEvent(document, 'mousedown', 'drag-down');
  39. removeEvent(document, 'mousemove', 'drag-move');
  40. removeEvent(document, 'mouseup', 'drag-up');
  41. }
  42. }
  43. }
  44.  
  45. function getDraggingDialog(e) {
  46. var target = e && e.target ? e.target : window.event.srcElement;
  47. while (target && target.className.indexOf('dialog-title') == -1) {
  48. target = target.offsetParent;
  49. }
  50. if (target != null) {
  51. return target.offsetParent;
  52. } else {
  53. return null;
  54. }
  55. }
  56.  
  57. Dragging(getDraggingDialog).enable();

边界处理

这个问题说起来也简单,可以在函数调用的时候传入边界值,每次移动的时候判断是否出了边界,这样改动一下

  1. var Dragging = function (conf) { //参数为验证点击区域是否为可移动区域,如果是返回欲移动元素,负责返回null
  2. var draggingObj = null; //dragging Dialog
  3. var diffX = 0, diffY = 0;
  4.  
  5. var minX = conf.left != undefined ? conf.left : Number.NEGATIVE_INFINITY;
  6. var maxX = conf.right != undefined ? conf.right : Number.POSITIVE_INFINITY;
  7. var minY = conf.top != undefined ? conf.top : Number.NEGATIVE_INFINITY;
  8. var maxY = conf.bottom != undefined ? conf.bottom : Number.POSITIVE_INFINITY;
  9.  
  10. var draggingObjWidth = 0,
  11. draggingObjHeight = 0;
  12.  
  13. function mouseHandler(e) {
  14. switch (e.type) {
  15. case 'mousedown':
  16. draggingObj = conf.validateHandler(e);//验证是否为可点击移动区域
  17. if (draggingObj != null) {
  18. diffX = e.clientX - draggingObj.offsetLeft;
  19. diffY = e.clientY - draggingObj.offsetTop;
  20. var size = draggingObj.getBoundingClientRect();
  21. draggingObjWidth = size.right - size.left;
  22. draggingObjHeight = size.bottom - size.top;
  23. }
  24. break;
  25.  
  26. case 'mousemove':
  27. if (draggingObj) {
  28. var x = e.clientX - diffX;
  29. var y = e.clientY - diffY;
  30. if (x > minX && x < maxX - draggingObjWidth) {
  31. draggingObj.style.left = x + 'px';
  32. }
  33. if (y > minY && y < maxY - draggingObjHeight) {
  34. draggingObj.style.top = y + 'px';
  35. }
  36. }
  37. break;
  38.  
  39. case 'mouseup':
  40. draggingObj = null;
  41. diffX = 0;
  42. diffY = 0;
  43. break;
  44. }
  45. };
  46.  
  47. return {
  48. enable: function () {
  49. addEvent(document, 'mousedown', 'drag-down', mouseHandler);
  50. addEvent(document, 'mousemove', 'drag-move', mouseHandler);
  51. addEvent(document, 'mouseup', 'drag-up', mouseHandler);
  52. },
  53. disable: function () {
  54. removeEvent(document, 'mousedown', 'drag-down');
  55. removeEvent(document, 'mousemove', 'drag-move');
  56. removeEvent(document, 'mouseup', 'drag-up');
  57. }
  58. }
  59. }
  60.  
  61. function getDraggingDialog(e) {
  62. var target = e && e.target ? e.target : window.event.srcElement;
  63. while (target && target.className.indexOf('dialog-title') == -1) {
  64. target = target.offsetParent;
  65. }
  66. if (target != null) {
  67. return target.offsetParent;
  68. } else {
  69. return null;
  70. }
  71. }
  72.  
  73. var config = {
  74. validateHandler: getDraggingDialog,
  75. top: document.documentElement.clientTop,
  76. right: document.documentElement.clientWidth,
  77. bottom: document.documentElement.clientHeight,
  78. left: document.documentElement.clientLeft
  79. }
  80.  
  81. Dragging(config).enable();

如果希望Dialog只能在可视窗口拖动,就可以像上面那样对config参数自定义四个边界值,如果仍然希望没有边界的拖动,则可以四个边界问题不处理,但是validateHandler属性是必须的。

拖动卡顿、失效

关于拖动卡顿在复杂的页面有位明显,一个重要原因就是拖动的时候计算太多导致,不要以为在若动的时候页面就仅仅处理拖动部分的代码,没拖动细微的一下页面都要进行reflow,计算布局所有页面元素的位置,所以复杂的页面自然会卡顿,我们能够处理的只能是是代码的计算尽量简单,为了防止误导读者,我在上面的版本中其实已经做了此项工作,把能够提前计算的的变量值尽量都在函数初始化、mousedown的时候做,再就是尽量使用值变量,避免JavaScript[频繁层层搜索变量引用,看一下低效版的拖动(可不要学会)

  1. function mouseHandler(e) {
  2. switch (e.type) {
  3. case 'mousedown':
  4. draggingObj = conf.validateHandler(e);//验证是否为可点击移动区域
  5. break;
  6.  
  7. case 'mousemove':
  8. if (draggingObj) {
  9. diffX = e.clientX - draggingObj.offsetLeft; //如果这两句也不定义变量,每次使用都要取event的属性值和draggingObj的属性值
  10. diffY = e.clientY - draggingObj.offsetTop;
  11. var size = draggingObj.getBoundingClientRect(); //每移动一下都要算一下大小,实际没必要,拖动不不会改变元素大小
  12.  
  13. if ((e.clientX - diffX) > minX && (e.clientX - diffX) < maxX - (size.right - size.left)) {//每次都要再算两遍e.clientX - diffX
  14. draggingObj.style.left = x + 'px';
  15. }
  16. if ((e.clientY - diffY) > minY && (e.clientY - diffY) < maxY - (size.bottom - size.top)) {//每次都要再算两遍e.clientY - diffY
  17. draggingObj.style.top = y + 'px';
  18. }
  19. }
  20. break;
  21.  
  22. case 'mouseup':
  23. draggingObj = null;
  24. diffX = 0;
  25. diffY = 0;
  26. minX = 0;
  27. break;
  28. }
  29. };

有同学会说了你都处理了为什么每次还是会拖着拖着就鼠标就出去了,然后就失效了呢?仔细看看每次失效的时候页面上中会伴随着文字被选中,而且仔细观察这个真的会影响拖动,处理一下,拖动的时候不允许选中文字

  1. .disable-select *
  2. {
  3. -moz-user-select: none;
  4. -ms-user-select: none;
  5. -webkit-user-select: none;
  6. user-select: none;
  7. }
  1. function mouseHandler(e) {
  2. switch (e.type) {
  3. case 'mousedown':
  4. draggingObj = conf.validateHandler(e);//验证是否为可点击移动区域
  5. if (draggingObj != null) {
  6. diffX = e.clientX - draggingObj.offsetLeft;
  7. diffY = e.clientY - draggingObj.offsetTop;
  8.  
  9. var size = draggingObj.getBoundingClientRect();
  10. draggingObjWidth = size.right - size.left;
  11. draggingObjHeight = size.bottom - size.top;
  12. document.body.className += ' disable-select'; //禁止选中
  13. document.body.onselectstart = function () { return false; };
  14. }
  15. break;
  16.  
  17. case 'mousemove':
  18. if (draggingObj) {
  19. var x = e.clientX - diffX;
  20. var y = e.clientY - diffY;
  21. if (x > minX && x < maxX - draggingObjWidth) {
  22. draggingObj.style.left = x + 'px';
  23. }
  24. if (y > minY && y < maxY - draggingObjHeight) {
  25. draggingObj.style.top = y + 'px';
  26. }
  27. }
  28. break;
  29.  
  30. case 'mouseup':
  31. draggingObj = null;
  32. diffX = 0;
  33. diffY = 0;
  34. document.body.className = document.body.className.replace(' disable-select', '');
  35. document.body.onselectstart = null;
  36. break;
  37. }
  38. };

最后

最后的源码就是这样的

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>Test</title>
  5. <style type="text/css">
  6. html, body
  7. {
  8. height: %;
  9. width: %;
  10. padding: ;
  11. margin: ;
  12. }
  13.  
  14. .dialog
  15. {
  16. width: 250px;
  17. height: 250px;
  18. position: absolute;
  19. background-color: #ccc;
  20. -webkit-box-shadow: 1px 1px 3px #;
  21. -moz-box-shadow: 1px 1px 3px #;
  22. box-shadow: 1px 1px 3px #;
  23. }
  24.  
  25. .dialog-title
  26. {
  27. color: #fff;
  28. background-color: #;
  29. font-size: 12pt;
  30. font-weight: bold;
  31. padding: 4px 6px;
  32. cursor: move;
  33. }
  34.  
  35. .dialog-content
  36. {
  37. padding: 4px;
  38. }
  39.  
  40. .disable-select *
  41. {
  42. -moz-user-select: none;
  43. -ms-user-select: none;
  44. -webkit-user-select: none;
  45. user-select: none;
  46. }
  47. </style>
  48. </head>
  49. <body>
  50. <div id="dlgTest" class="dialog">
  51. <div class="dialog-title">Dialog</div>
  52. <div class="dialog-content">
  53. This is a draggable test.
  54. </div>
  55. </div>
  56.  
  57. <script type="text/javascript">
  58. function addEvent(element, type, key, handler) {//绑定事件处理程序
  59. if (element[type + key])
  60. return false;
  61. if (typeof element.addEventListener != "undefined") {
  62. element[type + key] = handler;
  63. element.addEventListener(type, handler, false);
  64. }
  65. else {
  66. element['e' + type + key] = handler;
  67. element[type + key] = function () {
  68. element['e' + type + key](window.event); //解决IE浏览器event及this问题
  69. };
  70. element.attachEvent('on' + type, element[type + key]);
  71. }
  72. return true;
  73. }
  74.  
  75. function removeEvent(element, type, key) {//移除事件
  76. if (!element[type + key])
  77. return false;
  78.  
  79. if (typeof element.removeEventListener != "undefined") {
  80. element.removeEventListener(type, element[type + key], false);
  81. }
  82. else {
  83. element.detachEvent("on" + type, element[type + key]);
  84. element['e' + type + key] = null;
  85. }
  86.  
  87. element[type + key] = null;
  88. return true;
  89. }
  90. </script>
  91.  
  92. <script type="text/javascript">
  93. var Dragging = function (conf) { //参数为验证点击区域是否为可移动区域,如果是返回欲移动元素,负责返回null
  94. var draggingObj = null; //dragging Dialog
  95. var diffX = , diffY = ;
  96.  
  97. var minX = conf.left != undefined ? conf.left : Number.NEGATIVE_INFINITY;
  98. var maxX = conf.right != undefined ? conf.right : Number.POSITIVE_INFINITY;
  99. var minY = conf.top != undefined ? conf.top : Number.NEGATIVE_INFINITY;
  100. var maxY = conf.bottom != undefined ? conf.bottom : Number.POSITIVE_INFINITY;
  101.  
  102. var draggingObjWidth = ,
  103. draggingObjHeight = ;
  104.  
  105. function mouseHandler(e) {
  106. switch (e.type) {
  107. case 'mousedown':
  108. draggingObj = conf.validateHandler(e);//验证是否为可点击移动区域
  109. if (draggingObj != null) {
  110. diffX = e.clientX - draggingObj.offsetLeft;
  111. diffY = e.clientY - draggingObj.offsetTop;
  112.  
  113. var size = draggingObj.getBoundingClientRect();
  114. draggingObjWidth = size.right - size.left;
  115. draggingObjHeight = size.bottom - size.top;
  116. document.body.className += ' disable-select'; //禁止选中
  117. document.body.onselectstart = function () { return false; };
  118. }
  119. break;
  120.  
  121. case 'mousemove':
  122. if (draggingObj) {
  123. var x = e.clientX - diffX;
  124. var y = e.clientY - diffY;
  125. if (x > minX && x < maxX - draggingObjWidth) {
  126. draggingObj.style.left = x + 'px';
  127. }
  128. if (y > minY && y < maxY - draggingObjHeight) {
  129. draggingObj.style.top = y + 'px';
  130. }
  131. }
  132. break;
  133.  
  134. case 'mouseup':
  135. draggingObj = null;
  136. diffX = ;
  137. diffY = ;
  138. document.body.className = document.body.className.replace(' disable-select','');
  139. document.body.onselectstart = null;
  140. break;
  141. }
  142. };
  143.  
  144. return {
  145. enable: function () {
  146. addEvent(document, 'mousedown', 'drag-down', mouseHandler);
  147. addEvent(document, 'mousemove', 'drag-move', mouseHandler);
  148. addEvent(document, 'mouseup', 'drag-up', mouseHandler);
  149. },
  150. disable: function () {
  151. removeEvent(document, 'mousedown', 'drag-down');
  152. removeEvent(document, 'mousemove', 'drag-move');
  153. removeEvent(document, 'mouseup', 'drag-up');
  154. }
  155. }
  156. }
  157.  
  158. function getDraggingDialog(e) {
  159. var target = e && e.target ? e.target : window.event.srcElement;
  160. while (target && target.className.indexOf('dialog-title') == -) {
  161. target = target.offsetParent;
  162. }
  163. if (target != null) {
  164. return target.offsetParent;
  165. } else {
  166. return null;
  167. }
  168. }
  169.  
  170. var config = {
  171. validateHandler: getDraggingDialog,
  172. top: document.documentElement.clientTop,
  173. right: document.documentElement.clientWidth,
  174. bottom: document.documentElement.clientHeight,
  175. left: document.documentElement.clientLeft
  176. };
  177.  
  178. Dragging(config).enable();
  179. </script>
  180. </body>
  181. </html>

试试真的好了很多,然而鼠标要是移动的快还是会拖离,以为就是这样了呢,但试了试jQuery的Dialog控件,拖动基本流畅,这让人情何以堪,今天天气好,出去找妹子了,改天研究研究jQuery是怎么写的吧

可拖动的DIV续的更多相关文章

  1. jQuery实现鼠标拖动改变Div高度

    最近项目中需要在DashBoard页面做一个事件通知栏,该通知栏固定位于页面底部,鼠标拖动该DIV实现自动改变高度扩展内容显示区域. 以下是一个设计原型,基于jQuery实现,只实现了拖动效果,没有做 ...

  2. 鼠标拖动改变DIV等网页元素的大小的最佳实践

    1.初次实现 1.1 html代码 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" la ...

  3. jquery 拖动改变div大小

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. 可拖动的div——demo

    可拖动的div——demo 我们经常会遇到这样的注册界面 我们以前经常可以遇到这种需要注册的网站,如上图: 上图有一个特点,即是上述注册框其实是一个div,同时可以拖动,以下做一个简单的实例,就可以实 ...

  5. 可拖动的DIV

    在做WEB UI设计的时候,拖动某个HTML元素已经成为一种不能忽视的用户界面模式,比较典型的应用例子就是Dialog,一个元素是怎么实现拖动的呢?其实原理非常简单,要想实现首先得了解几个基本知识. ...

  6. 【转】弹出可拖动的DIV层提示窗口

    来源:www.divcss5.com <html> <head> <meta http-equiv="Content-Type" content=&q ...

  7. 创建一个可拖动的DIV

    var drag = function(){ var obj = document.getElementById("id"); var s = obj.style; var b = ...

  8. [置顶] 原创鼠标拖动实现DIV排序

    先上效果图: 对比传统的排序,这是一个很不错的尝试,希望对大家有启发. 大家可以参考我的上一篇博文:http://blog.csdn.net/littlebo01/article/details/12 ...

  9. 如何用JavaScript做一个可拖动的div层

    可拖动的层在Web设计中用处很多,比如在某些需要自定义风格布局的应用中,控件就需要拖动操作,下面介绍一个,希望可以满足你的需求,顺便学习一下可拖动的层是如何实现的. 下面是效果演示: 这个DIV可以移 ...

随机推荐

  1. C#窗口应用如何居中

    在form的属性设置里面有一个初始位置的设置(startposion)设置成centerscreen(屏幕居中即可)

  2. Hadoop2.6.0配置参数查看小工具

    前言 使用Hadoop进行离线分析或者数据挖掘的工程师,经常会需要对Hadoop集群或者mapreduce作业进行性能调优.也许你知道通过浏览器访问http://master:18088/conf来查 ...

  3. SQL Server客户端登录名与数据库用户关联

    数据库迁移之后,在新的SQL Server客户端工具设置关联时,往往会报错: 用户.组或角色 'XXX' 在当前数据库中已存在. 解决方法: 首先介绍一下sql server中“登录”与“用户”的区别 ...

  4. max min 与 min max 的差别

    在求解最优化问题时,遇到一个对偶问题的转换:对于形如 的问题,可以转换为求解 即原问题的对偶问题.而在一般情况下: 对于这个为题的说明我参照http://math.stackexchange.com/ ...

  5. loop 循环次数

    在汇编中可以使用 loop 段地址:偏移地址 并配合 cx 达到循环执行的目的,但是在一些资料中看到说,cx 是循环的次数,我觉得这是不对的. 比如下面这段代码的作用是使得最终的 ax 中的值为 3 ...

  6. LocalDB-排序规则:中文乱码; DefaultLanguage

    DefaultLanguage: Set Language 简体中文|us_english SELECT SYSTEM_USER Login SP_DefaultLanguage #Login, 简体 ...

  7. 【洛谷P3385】模板-负环

    这道题普通的bfs spfa或者ballen ford会T 所以我们使用dfs spfa 原因在于,bfs sfpa中每个节点的入队次数不定,退出操作不及时,而dfs则不会 既然,我们需要找负环,那么 ...

  8. java读取properties配置文件总结

    java读取properties配置文件总结 在日常项目开发和学习中,我们不免会经常用到.propeties配置文件,例如数据库c3p0连接池的配置等.而我们经常读取配置文件的方法有以下两种: (1) ...

  9. 我与solr(五)--关于schema.xml中的相关配置的详解

    先把文件的代码贴上来: <?xml version="1.0" encoding="UTF-8" ?> <!-- 版权说明... --> ...

  10. 【Visual Lisp】图元选择集专题

    图元选择集专题;;★★★01.选择集操作★★★(setq ss (ssadd));;创建一个空选择集(ssadd (car(entsel)) ss);;将点取的图元添加到ss选择集中,可以不用setq ...