怎么用 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:

 
 
你现在拥有了拖拽的所有东西.

下面的三个demo是记录事件历史.当你的鼠标在item上移动,将记录所生的事件,如果你不明白可以尝试一下鼠标的划过或者拖动,看有什么发生.

--------------------------------------------------------------
点此查看示例六
--------------------------------------------------------------

转载自: http://www.codebit.cn/pub/html/javascript/tutorial/how_to_drag_and_drop_in_javascript/
这是一篇翻译文章,原文地址:
http://www.webreference.com/programming/javascript/mk/column2/index.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值