`

怎么用 javascript 实现拖拽

阅读更多

在网页上实现拖拽其实不难,第一我们需要知道鼠标的位置,第二我们需要知道当用户点击一个网页元素时这个元素要能够拖拽。

--------------------------------------------------------------
点此查看示例一
--------------------------------------------------------------

获取鼠标移动信息

开始我们需要获取鼠标的坐标.我们添加一个document.onmousemove 就可以达到此目的:

Javascript:

  1.  
  2. document.onmousemove = mouseMove;
  3.  
  4. function mouseMove(ev){
  5. ev = ev || window.event;
  6. var mousePos = mouseCoords(ev);
  7. }
  8.  
  9. function mouseCoords(ev){
  10. if(ev.pageX || ev.pageY){
  11. return {x:ev.pageX, y:ev.pageY};
  12. }
  13. return {
  14. x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
  15. y:ev.clientY + document.body.scrollTop - document.body.clientTop
  16. };
  17. }
  18.  



--------------------------------------------------------------
点此查看示例二
--------------------------------------------------------------

我们首先要声明一个  evnet 对象,无论移动、点击、按键等,都会激活一个 evnet ,在 Internet Explorer 里, event 是全局变量,会被存储在 window.event 里. 在 firefox 或者其他浏览器,event 会被相应的函数获取.当我们将mouseMove函数赋值于document.onmousemove,mouseMove 会获取鼠标移动事件。

为了让 ev 在所有浏览器下获取了 event 事件,在Firefox下"||window.event"将不起作用,因为ev已经有了赋值。在 MSIE 中 ev 为空,所以得到 window.event 。

因为在这篇文章中我们需要多次获取鼠标位置,所以我们设计了一个 mouseCoords 函数,它包含一个参数 : event 。

因为我们要在 MSIE 和其他浏览器下运行,Firefox 和其他浏览器用 event.pageX 和 event.pageY 来表示鼠标相对于文档的位置,如果你有一个 500*500 的窗口并且你的鼠标在绝对中间,那么 pageX 和 pageY  的值都是 250,如果你向下滚动 500, 那么 pageY 将变成 750。

MSIE 正好相反,它使用 event.clientX 和 event.clientY 表示鼠标相当于窗口的位置,而不是文档。在同样的例子中,如果你向下滚动500,clientY 依然是 250,因此,我们需要添加 scrollLeft 和 scrollTop 这两个相对于文档的属性。最后,MSIE 中文档并不是从 0,0 开始,而是通常有一个小的边框(通常是 2 象素),边框的大小定义在 document.body.clientLeft 和 clientTop 中,我们也把这些加进去。

很幸运,我们现在已经用 mouseCoords 函数解决了坐标问题,不需为此费心了。

捕捉鼠标点击

下面我们需要知道鼠标什么时候点击和什么时候释放,如果你跳过此步,当你的鼠标移动到这些可拖动的元素是,他们就开始“拖动”了,这将是非常恼人并且违反直觉的。

这里有两个函数帮助我们:onmousedown 和 onmouseup ,我们预先设置一个函数获取 document.onmousedown 和 document.onmouseup,这样看起来我们已经能够获取 document.onmousedown 和 document.onmouseup,但是,当我们获取了 document.onmousedown ,同时也激活了点击属性,如:text, images, tables 等,但是我们只想取得那些能够拖动得属性,所有我们设置函数来获取我们想要移动的对象。

Javascript:

  1.  
  2. document.onmouseup = mouseUp;
  3. var dragObject = null;
  4.  
  5. function makeClickable(object){
  6. object.onmousedown = function(){
  7. dragObject = this;
  8. }
  9. }
  10.  
  11. function mouseUp(ev){
  12. dragObject = null;
  13. }
  14.  



我们现在有了一个可定义的 dragObject,它获取你点击的任意元素,如果你释放鼠标按钮, dragObject 被清空,所以如果 dragObject != null ,我们就知道我们可能在拖动着什么。

--------------------------------------------------------------
点此查看示例三
--------------------------------------------------------------

移动一个元素

我们现在已经知道如何捕捉鼠标的移动和点击,剩下的就是拖动了,
首先,要明确我们想要拖动的位置,将 position 设置为 “absolute” 意味着当你设置  style.top 或 style.left ,这个尺度是从页面的 top-left 开始算的,这样我们就可以继续了。

当我们设置 item.style.position='absolute',所有的需要做的就是改变 top 或 left 的值,这样就可以移动了。

Javascript:

  1.  
  2. document.onmousemove = mouseMove;
  3. document.onmouseup = mouseUp;
  4.  
  5. var dragObject = null;
  6. var mouseOffset = null;
  7.  
  8. function getMouseOffset(target, ev){
  9. ev = ev || window.event;
  10.  
  11. var docPos = getPosition(target);
  12. var mousePos = mouseCoords(ev);
  13. return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
  14. }
  15.  
  16. function getPosition(e){
  17. var left = 0;
  18. var top = 0;
  19.  
  20. while (e.offsetParent){
  21. left += e.offsetLeft;
  22. top += e.offsetTop;
  23. e = e.offsetParent;
  24. }
  25.  
  26. left += e.offsetLeft;
  27. top += e.offsetTop;
  28.  
  29. return {x:left, y:top};
  30. }
  31.  
  32. function mouseMove(ev){
  33. ev = ev || window.event;
  34. var mousePos = mouseCoords(ev);
  35.  
  36. if(dragObject){
  37. dragObject.style.position = 'absolute';
  38. dragObject.style.top = mousePos.y - mouseOffset.y;
  39. dragObject.style.left = mousePos.x - mouseOffset.x;
  40.  
  41. return false;
  42. }
  43. }
  44. function mouseUp(){
  45. dragObject = null;
  46. }
  47.  
  48. function makeDraggable(item){
  49. if(!item) return;
  50. item.onmousedown = function(ev){
  51. dragObject = this;
  52. mouseOffset = getMouseOffset(this, ev);
  53. return false;
  54. }
  55. }
  56.  



--------------------------------------------------------------
点此查看示例四
--------------------------------------------------------------

你可能注意到这些代码基本上是前面的集合,将前面的示例合在一起,就可以实现拖拽了。

当我们点击一个元素,我们还会获取其他变量,mouseOffset 定义着我们的鼠标位置,如果我们有一个 20*20 的图片,并且点击在它的中间,那么 mouseOffset 就是 {x:10, y:10},如果点击在图片的 top-left ,这个值就是  {x:0, y:0} 。我们用这些方法获取我们的鼠标和图片的信息,如果忽略这些,我们将永远处在相同的元素位置。

我们的 mouseOffset 函数使用了另外的函数 getPosition,getPosition 的目的是返回元素相当于文档的位置,我们仅仅读取 item.offsetLeft 或 item.style.left ,将得到元素相对于其父元素的位置,而不是整个文档,所有的脚本都是相对于文档,这样就会好一些。

为了完成 getPosition 的任务,必须循环取得此的父级,我们将得到元素的 left-top 的位置.我们可以管理想要的 top 与 left 列表.

当我们有了这些信息,并且移动鼠标,mouseMove 将一直运行,首先,我们要确定元素的 style.position 是 absolute,接着我们拖拽元素到任何我们我们已经定义好的位置,当鼠标释放,dragObject  被重置, mouseMove 将不再做任何事情。

拖拽一个元素

前面的例子目的很简单,就是拖拽item到我们希望到的地方.我们经常还有其他目的如删除item,比如我们可以将item拖到垃圾桶里,或者其他页面定义的位置.

很不幸,我们有一个很大的难题,当我们拖拽,item会在鼠标之下,比如mouseove,mousedown,mouseup或者其他mouse action.如果我们拖拽一个item到垃圾桶上,鼠标信息还在item上,不在垃圾桶上.

怎么解决这个问题呢?有几个方法可以来解决.第一,这是以前比较推荐的,我们在移动鼠标时item会跟随鼠标,并占用了mouseover/mousemove等鼠标事件,我们不这样做,只是让item跟随着鼠标,并不占用mouseover等鼠标事件,这样会解决问题,但是这样并不好看,我们还是希望item能直接跟在mouse下.

另一个选择是不做item的拖拽.你可以改变鼠标指针来显示需要拖拽的item,然后放在鼠标释放的位置.这个解决方案,也是因为美学原因不予接受.

最后的解决方案是,我们并不去除拖拽效果.这种方法比前两种繁杂许多,我们需要定义我们需要释放目标的列表,当鼠标释放时,手工去检查释放的位置是否是在目标列表位置上,如果在,说明是释放在目标位置上了.

Javascript:

  1.  
  2. /*
  3. All code from the previous example is needed with the exception
  4. of the mouseUp function which is replaced below
  5. */
  6.  
  7. var dropTargets = [];
  8.  
  9. function addDropTarget(dropTarget){
  10. dropTargets.push(dropTarget);
  11. }
  12.  
  13. function mouseUp(ev){
  14. ev = ev || window.event;
  15. var mousePos = mouseCoords(ev);
  16.  
  17. for(var i=0; i<dropTargets.length; i++){
  18. var curTarget = dropTargets[i];
  19. var targPos = getPosition(curTarget);
  20. var targWidth = parseInt(curTarget.offsetWidth);
  21. var targHeight = parseInt(curTarget.offsetHeight);
  22.  
  23. if(
  24. (mousePos.x > targPos.x) &&
  25. (mousePos.x < (targPos.x + targWidth)) &&
  26. (mousePos.y > targPos.y) &&
  27. (mousePos.y < (targPos.y + targHeight))){
  28. // dragObject was dropped onto curTarget!
  29. }
  30. }
  31.  
  32. dragObject = null;
  33. }
  34.  



--------------------------------------------------------------
点此查看示例五
--------------------------------------------------------------

鼠标释放时会去取是否有drop属性,如果存在,同时鼠标指针还在drop的范围内,执行drop操作.我们检查鼠标指针位置是否在目标范围是用(mousePos.x>targetPos.x),而且还要符合条件(mousePos.x<(targPos.x + targWidth)).如果所有的条件符合,说明指针确实在范围内,可以执行drop指令了.

把所有的内容集合到一起

最后我们拥有了所有的drag/drop的脚本片断!下一个事情是我们将创建一个DOM处理。

下面的代码将创建container(容器),而且使任何一个需要drag/drop的item变成一个容器的item.代码在这个文章第二个demo的后面,它可以用户记录一个list(列表),定为一个导航窗口在左边或者右边,或者更多的函数你可以想到的.

下一步我们将通过"假代码"让reader看到真代码,下面为推荐:

  • 当document第一次载入时,创建dragHelper DIV.dragHelper将给移动的item加阴影.真实的item没有被dragged,只是用了insertBefor和appendChild来移动了,我们隐藏了dragHelper
  • 有了mouseDown与mouseUp函数.所有的操作会对应到当到iMouseDown的状态中,只有当mouse左键为按下时iMouseDown才为真,否则为假.
  • 我们创建了全局变量DragDrops与全局函数CreateDragContainer.DragDrops包含了一系列相对彼此的容器.任何参数(containers)将通过CreatedcragContainer进行重组与序列化,这样可以自由的移动.CreateDragContainer函数也将item进行绑定与设置属性.
  • 现在我们的代码知道每个item的加入,当我们移动处mouseMove,mouseMove函数首先会设置变量target,鼠标移动在上面的item,如果这个item在容器中(checked with getAttribute):
    • 运行一小段代码来改变目标的样式.创造rollover效果
    • 检查鼠标是否没有放开,如果没有
      • 设置curTarget代表当前item
      • 记录item的当前位置,如果需要的话,我们可以将它返回
      • 克隆当前的item到dragHelper中,我们可以移动带阴影效果的item.
      • item拷贝到dragHelper后,原有的item还在鼠标指针下,我们必须删除掉dragObj,这样脚本起作用,dragObj被包含在一个容器中.
      • 抓取容器中所有的item当前坐标,高度/宽度,这样只需要记录一次,当item被drag时,每随mouse移动,每移钟就会记录成千上万次.
    • 如果没有,不需要做任何事,因为这不是一个需要移动的item
  • 检查curTarget,它应该包含一个被移动的item,如果存在,进行下面操作
    • 开始移动带有阴影的item,这个item就是前文所创建的
    • 检查每个当前容器中的container,是否鼠标已经移动到这些范围内了
      • 我们检查看一下正在拖动的item是属于哪个container
      • 放置item在一个container的某一个item之前,或者整个container之后
      • 确认item是可见的
    • 如果鼠标不在container中,确认item是不可见了.
  • 剩下的事就是捕捉mouseUp的事件了



Javascript:

  1.  
  2. // iMouseDown represents the current mouse button state: up or down
  3. /*
  4. lMouseState represents the previous mouse button state so that we can
  5. check for button clicks and button releases:
  6. if(iMouseDown && !lMouseState) // button just clicked!
  7. if(!iMouseDown && lMouseState) // button just released!
  8. */
  9. var mouseOffset = null;
  10. var iMouseDown = false;
  11. var lMouseState = false;
  12. var dragObject = null;
  13.  
  14. // Demo 0 variables
  15. var DragDrops = [];
  16. var curTarget = null;
  17. var lastTarget = null;
  18. var dragHelper = null;
  19. var tempDiv = null;
  20. var rootParent = null;
  21. var rootSibling = null;
  22.  
  23. Number.prototype.NaN0=function(){return isNaN(this)?0:this;}
  24.  
  25. function CreateDragContainer(){
  26. /*
  27. Create a new "Container Instance" so that items from one "Set" can not
  28. be dragged into items from another "Set"
  29. */
  30. var cDrag = DragDrops.length;
  31. DragDrops[cDrag] = [];
  32.  
  33. /*
  34. Each item passed to this function should be a "container". Store each
  35. of these items in our current container
  36. */
  37. for(var i=0; i<arguments.length; i++){
  38. var cObj = arguments[i];
  39. DragDrops[cDrag].push(cObj);
  40. cObj.setAttribute('DropObj', cDrag);
  41.  
  42. /*
  43. Every top level item in these containers should be draggable. Do this
  44. by setting the DragObj attribute on each item and then later checking
  45. this attribute in the mouseMove function
  46. */
  47. for(var j=0; j<cObj.childNodes.length; j++){
  48.  
  49. // Firefox puts in lots of #text nodes...skip these
  50. if(cObj.childNodes[j].nodeName=='#text') continue;
  51.  
  52. cObj.childNodes[j].setAttribute('DragObj', cDrag);
  53. }
  54. }
  55. }
  56.  
  57. function mouseMove(ev){
  58. ev = ev || window.event;
  59.  
  60. /*
  61. We are setting target to whatever item the mouse is currently on
  62. Firefox uses event.target here, MSIE uses event.srcElement
  63. */
  64. var target = ev.target || ev.srcElement;
  65. var mousePos = mouseCoords(ev);
  66.  
  67. // mouseOut event - fires if the item the mouse is on has changed
  68. if(lastTarget && (target!==lastTarget)){
  69. // reset the classname for the target element
  70. var origClass = lastTarget.getAttribute('origClass');
  71. if(origClass) lastTarget.className = origClass;
  72. }
  73.  
  74. /*
  75. dragObj is the grouping our item is in (set from the createDragContainer function).
  76. if the item is not in a grouping we ignore it since it can't be dragged with this
  77. script.
  78. */
  79. var dragObj = target.getAttribute('DragObj');
  80.  
  81. // if the mouse was moved over an element that is draggable
  82. if(dragObj!=null){
  83.  
  84. // mouseOver event - Change the item's class if necessary
  85. if(target!=lastTarget){
  86. var oClass = target.getAttribute('overClass');
  87. if(oClass){
  88. target.setAttribute('origClass', target.className);
  89. target.className = oClass;
  90. }
  91. }
  92.  
  93. // if the user is just starting to drag the element
  94. if(iMouseDown && !lMouseState){
  95. // mouseDown target
  96. curTarget = target;
  97.  
  98. // Record the mouse x and y offset for the element
  99. rootParent = curTarget.parentNode;
  100. rootSibling = curTarget.nextSibling;
  101.  
  102. mouseOffset = getMouseOffset(target, ev);
  103.  
  104. // We remove anything that is in our dragHelper DIV so we can put a new item in it.
  105. for(var i=0; i<dragHelper.childNodes.length; i++) dragHelper.removeChild(dragHelper.childNodes[i]);
  106.  
  107. // Make a copy of the current item and put it in our drag helper.
  108. dragHelper.appendChild(curTarget.cloneNode(true));
  109. dragHelper.style.display = 'block';
  110.  
  111. // set the class on our helper DIV if necessary
  112. var dragClass = curTarget.getAttribute('dragClass');
  113. if(dragClass){
  114. dragHelper.firstChild.className = dragClass;
  115. }
  116.  
  117. // disable dragging from our helper DIV (it's already being dragged)
  118. dragHelper.firstChild.removeAttribute('DragObj');
  119.  
  120. /*
  121. Record the current position of all drag/drop targets related
  122. to the element. We do this here so that we do not have to do
  123. it on the general mouse move event which fires when the mouse
  124. moves even 1 pixel. If we don't do this here the script
  125. would run much slower.
  126. */
  127. var dragConts = DragDrops[dragObj];
  128.  
  129. /*
  130. first record the width/height of our drag item. Then hide it since
  131. it is going to (potentially) be moved out of its parent.
  132. */
  133. curTarget.setAttribute('startWidth', parseInt(curTarget.offsetWidth));
  134. curTarget.setAttribute('startHeight', parseInt(curTarget.offsetHeight));
  135. curTarget.style.display = 'none';
  136.  
  137. // loop through each possible drop container
  138. for(var i=0; i<dragConts.length; i++){

相关推荐

    原生javascript实现拖拽改变table表格行高(html)

    通过查看和分析这个文件,你可以更深入地了解如何用原生JavaScript实现拖拽改变表格行高的具体细节。 最后,这样的功能可以广泛应用于数据展示、编辑表格等场景,让用户可以根据需要自由调整表格的布局,提高其在...

    javaScript实现DIV简单拖拽

    javaScript实现DIV简单拖拽

    【JavaScript源代码】JavaScript实现拖动滑块拼图验证功能(html5、canvas).docx

    JavaScript实现的拖动滑块拼图验证功能是一种常见的安全验证机制,它被广泛应用于网站登录、注册等场景,以防止自动化的机器人或恶意攻击。这种验证方式要求用户手动将一个可拖动的图像块(通常是滑块)拖动到正确的...

    JavaScript实现超酷拖拽式列表

    JavaScript实现超酷拖拽式列表代码

    javascript实现鼠标拖动div的效果

    以上就是使用JavaScript实现鼠标拖动div效果的基本步骤。这个功能在许多交互式应用和网页设计中都有广泛的应用,如拖放组件、可移动的对话框等。通过熟练掌握这一技术,开发者可以为用户提供更加直观和便捷的操作...

    javascript实现用鼠标拖动页面的效果

    javascript实现用鼠标拖动页面的效果,而不是传统意义上的拖动一个层的效果

    JavaScript+css实现拖拽效果

    本文将详细讲解如何使用JavaScript和CSS来实现这一效果,以创建一个可拖拽的元素并处理其在页面上的位置。 首先,我们需要理解JavaScript在拖放功能中的角色。JavaScript提供了`dragstart`、`drag`、`dragend`以及`...

    javascript实现拖拽效果

    原声JS实现拖拽效果,带有详细思路、注释。原声JS实现拖拽效果,带有详细思路、注释。

    Javascript jquery 实现 拖拽, 和吸附功能

    在JavaScript和jQuery的世界里,实现元素的拖拽(Draggable)和吸附(Docking)功能是一项常见的需求,尤其是在创建交互式用户界面时。本篇将深入讲解如何利用这两种技术来增强网页的动态性和用户体验。 首先,...

    javascript实现拖动层特效

    javascript实现拖动层特效 请多多支持多多支持多多支持

    原生JavaScript实现滑块拖动

    自己写的原生JavaScript实现滑块拖动,样式随便写的,想要好看的需要自己修改。

    JavaScript 实现图片拖拽

    以上就是使用JavaScript实现图片拖拽的基本步骤和关键代码。通过这种方式,我们可以为用户提供更直观、更具互动性的网页体验。在实际项目中,还可以根据需求进行扩展,例如添加图片缩放、旋转等更多功能。

    SuperMap iclient for javascript实现拖拽要素

    常见的鼠标交互中经常见到单击,双击,悬浮等;本范例展示了在SuperMap iClient for javascript中如何使用SuperMap.Control.DragFeature实现拖拽要素的鼠标交互并对其各阶段事件进行监听。

    Javascript实现网页元素拖拽排序

    `dragend`事件处理函数是实现拖拽排序的关键。在这里,我们需要找到元素的新位置,并更新DOM结构。这通常涉及到查找元素的前后兄弟节点,然后将元素插入到正确的位置。 ```javascript function dragEndHandler...

    JavaScript实现拖动滑块验证(html5、canvas)

    JavaScript实现拖动滑块验证(html5、canvas)

    纯JavaScript 实现页面元素的拖拽效果,绝对精彩

    纯JavaScript 实现页面元素的拖拽效果,绝对精彩,可以容易实现与后台交互。

    Javascript实现DIV拖拽和添加

    本教程将详细讲解如何使用纯JavaScript实现这一功能,无需依赖任何外部库,如jQuery或类似的框架。 首先,我们需要创建一个可拖动的DIV元素。HTML代码可能如下所示: ```html ;height:100px;background-color:red;...

    用JavaScript实现图片切割效果实例

    总结来说,用JavaScript实现图片切割效果需要理解HTML5 Canvas的使用,熟练掌握Canvas API,以及对用户交互的处理。通过这样的实例,我们可以提升Web应用的用户体验,创造更加生动和丰富的视觉效果。

    javascript实现表格的单元格拖动排序

    javascript实现表格的单元格拖动排序,对实现图片的拖动排序有启发

    JavaScript鼠标拖拽

    通过这样的组合,你可以实现一个基本的JavaScript鼠标拖拽功能。当然,实际应用中可能还需要考虑边界限制、防抖处理以及在其他设备(如触摸屏)上的兼容性等问题,这些都是进阶话题,但对于初学者来说,理解以上基础...

Global site tag (gtag.js) - Google Analytics