一直以来,都对JS获取元素的位置感到非常的困惑:一会client、一会offset、一会scroll。

再加上各大浏览器之间的不兼容,唉,搞得哥晕晕乎乎的。

而很多页面效果都要用到这些位置。不得已,得练练,得记记。

下面就来说说这个基于 JQuery的简易拖拽插件吧。   

按惯例,先说说拖拽的原理,以及搞这么一个东东的步骤:

那什么是拖拽呢? 看名字就知道了:就是把一个东东拖来拽去的。 放到我们的DOM上,就是改变它的位置。

它只有两个难点:1、如何知道是在拖? 2、如何知道从哪拖,拖到哪?

其实,这也算不上难点,毕竟两者都是基础的东西,关键在于熟练。

换到js 中,我们搞一个拖拽效果,大致有如下步骤:

1、让元素捕获事件(一般情况下,无非就是mousedown、mousemove、mouseup)

2、在mousedown时,标记开始拖拽,并获取元素及鼠标的位置。

3、在mousemove时,不断的获取鼠标的新位置,并通过相应的位置算法,来重新定位元素位置。

4、在mouseup时,结束拖拽。。。然后周而复始。

这中间,个需要注意的地方:被拖拽的元素,至少需要相对或绝对定位,否则拖拽不会有效果。

OK,不多说,无代码,无真相。相应的解释都在其中了:


<! 
   DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" 
   > 
   
 
   < 
   html  
   xmlns 
   ="http://www.w3.org/1999/xhtml" 
   > 
   
 
   < 
   head 
   > 
   
 
   < 
   meta  
   http-equiv 
   ="Content-Type" 
    content 
   ="text/html; charset=utf-8" 
   /> 
   
 
   < 
   title 
   > 
   Jeremy - DragDrop Test ! 
   </ 
   title 
   > 
   
 
   < 
   meta  
   name 
   ="keywords" 
    content 
   ="Javascript自由拖拽类" 
     
   /> 
   
 
   < 
   script  
   type 
   ="text/javascript" 
    src 
   ="jquery-1.4.2.min.js" 
   ></ 
   script 
   > 
   

 
   < 
   script  
   type 
   ="text/javascript" 
   > 
   
 ( 
   function 
   ($)
 {
 $.extend({  
    // 
   获取鼠标当前坐标 
     
    mouseCoords: 
   function 
   (ev){  
    if 
   (ev.pageX  
   || 
    ev.pageY){  
     
    {x:ev.pageX, y:ev.pageY};}  
    return 
    x:ev.clientX  
   + 
    document.body.scrollLeft  
   - 
    y:ev.clientY  
   + 
    document.body.scrollTop  
   - 
    };   
    // 
   获取样式值 
     
    getStyle: 
   function 
   (obj,styleName)   {
 
    return 
    obj.currentStyle  
   ? 
    obj.currentStyle[styleName] : document.defaultView.getComputedStyle(obj, 
   null 
   )[styleName];
 
   // 
    return obj.currentStyle ? obj.currentStyle[styleName] : document.defaultView.getComputedStyle(obj,null).getPropertyValue(styleName); 
   
 
    } }); 
 
    // 
    元素拖拽插件 
   
 
    $.fn.dragDrop  
   = 
     
   function 
   (options)
 {
 
    var 
    opts  
   = 
    $.extend({},$.fn.dragDrop.defaults,options);
 
    return 
     
   this 
   .each( 
   function 
   (){
 
    // 
   是否正在拖动 
   
 
      
   var 
    bDraging  
   = 
     
   false 
   ;  
    // 
   移动的元素 
   
 
      
   var 
    moveEle  
   = 
    $( 
   this 
   );
 
    // 
   点击哪个元素,以触发移动。 
     
     
   // 
   该元素需要是被移动元素的子元素(比如标题等) 
   
 
      
   var 
    focuEle  
   = 
    opts.focuEle  
   ? 
    $(opts.focuEle,moveEle) : moveEle ;
 
    if 
   ( 
   ! 
   focuEle  
   || 
    focuEle.length 
   <= 
   0 
   )
 {
 alert( 
   ' 
   focuEle is not found! the element must be a child of  
   ' 
   + 
   this 
   .id);
 
    return 
     
   false 
   ;
 } 
 
    // 
    initDiffX|Y : 初始时,鼠标与被移动元素原点的距离 
   
 
      
   // 
    moveX|Y : 移动时,被移动元素定位位置 (新鼠标位置与initDiffX|Y的差值) 
   
 
      
   // 
    如果定义了移动中的回调函数,该对象将以参数传入回调函数。 
   
  
     
   var 
    dragParams  
   = 
    {initDiffX: 
   '' 
   ,initDiffY: 
   '' 
   ,moveX: 
   '' 
   ,moveY: 
   '' 
   };  
    // 
   被移动元素,需要设置定位样式,否则拖拽效果将无效。 
   
 
     moveEle.css({ 
   ' 
   position 
   ' 
   : 
   ' 
   absolute 
   ' 
   , 
   ' 
   left 
   ' 
   : 
   ' 
   0 
   ' 
   , 
   ' 
   top 
   ' 
   : 
   ' 
   0 
   ' 
   });
 
    // 
   点击时,记录鼠标位置 
     
     
   // 
   DOM写法: getElementById('***').οnmοusedοwn= function(event); 
   
 
     focuEle.bind( 
   ' 
   mousedown 
   ' 
   , 
   function 
   (e){  
    // 
   标记开始移动 
   
 
     bDraging  
   = 
     
   true 
   ;
 
     // 
   改变鼠标形状 
   
 
     moveEle.css({ 
   ' 
   cursor 
   ' 
   : 
   ' 
   move 
   ' 
   });  
     
   捕获事件。(该用法,还有个好处,就是防止移动太快导致鼠标跑出被移动元素之外) 
   
 
      
   if 
   (moveEle.get( 
   0 
   ).setCapture)
  { 
 moveEle.get( 
   0 
   ).setCapture();   }  
 
    // 
   (实际上是鼠标当前位置相对于被移动元素原点的距离) 
     
     
   // 
    DOM写法:(ev.clientX + document.body.scrollLeft - document.body.clientLeft) - document.getElementById('***').style.left; 
   
 
    dragParams.initDiffX  
   = 
    $.mouseCoords(e).x  
   - 
    dragParams.initDiffY  
   = 
    $.mouseCoords(e).y  
   - 
    moveEle.position().top;
  });
 
    // 
   移动过程 
   
 
     focuEle.bind( 
   ' 
   mousemove 
   ' 
   , 
   function 
   (e){
 
    if 
   (bDraging)
 { 
 
    // 
   被移动元素的新位置,实际上鼠标当前位置与原位置之差 
     
     
   // 
   实际上,被移动元素的新位置,也可以直接是鼠标位置,这也能体现拖拽,但是元素的位置就不会精确。 
     
     
   = 
    $.mouseCoords(e).x  
   - 
    dragParams.moveY  
   = 
    $.mouseCoords(e).y  
   - 
    dragParams.initDiffY;
 
    // 
   是否限定在某个区域中移动. 
   
 
      
   // 
   fixarea格式: [x轴最小值,x轴最大值,y轴最小值,y轴最大值] 
   
 
      
   if 
   (opts.fixarea)
 { 
 
    if 
   (dragParams.moveX 
   < 
   opts.fixarea[ 
   0 
   ])  {
 dragParams.moveX 
   = 
   opts.fixarea[ 
   0 
   ]  }
 
    if 
   (dragParams.moveX 
   > 
   opts.fixarea[ 
   1 
   ])
 {
 dragParams.moveX 
   = 
   opts.fixarea[ 
   1 
   ]
 }
 
    if 
   (dragParams.moveY 
   < 
   opts.fixarea[ 
   2 
   ])
 {  dragParams.moveY 
   = 
   opts.fixarea[ 
   2 
   ]
 }
 
    if 
   (dragParams.moveY 
   > 
   opts.fixarea[ 
   3 
   ])
 {
 dragParams.moveY 
   = 
   opts.fixarea[ 
   3 
   ]
 }   }
 
    // 
   移动方向:可以是不限定、垂直、水平。 
   
 
      
   if 
   (opts.dragDirection 
   == 
   ' 
   all 
   ' 
   )
 {
 
    // 
   DOM写法: document.getElementById('***').style.left = '***px';  
   
 
     moveEle.css({ 
   ' 
   left 
   ' 
   :dragParams.moveX, 
   ' 
   top 
   ' 
   :dragParams.moveY});
 }
 
    else 
     
   if 
    (opts.dragDirection 
   == 
   ' 
   vertical 
   ' 
   )
 {
 moveEle.css({ 
   ' 
   top 
   ' 
   :dragParams.moveY});
 }
 
    else 
     
   if 
   (opts.dragDirection 
   == 
   ' 
   horizontal 
   ' 
   )
 {
 moveEle.css({ 
   ' 
   left 
   ' 
   :dragParams.moveX});
 }
 
    // 
   如果有回调 
   
 
      
   if 
   (opts.callback)  {
 
    // 
   将dragParams作为参数传递 
   
 
     opts.callback.call(opts.callback,dragParams);
 }
 }
  });
 // 
   鼠标弹起时,标记为取消移动 
     
     
   ' 
   mouseup 
   ' 
   , 
   function 
   (e){
 bDraging 
   = 
   false 
   ;
 moveEle.css({ 
   ' 
   cursor 
   ' 
   : 
   ' 
   default 
   ' 
   });
 
    if 
   (moveEle.get( 
   0 
   ).releaseCapture)
 {
 moveEle.get( 
   0 
   ).releaseCapture();
 }
 });  });
 };
 
    // 
   默认配置 
     
    $.fn.dragDrop.defaults  
   = 
    
 {
 focuEle: 
   null 
   ,  
   // 
   点击哪个元素开始拖动,可为空。不为空时,需要为被拖动元素的子元素。 
     
     
   null 
   ,  
   // 
   拖动时触发的回调。 
   
 
    dragDirection: 
   ' 
   all 
   ' 
   ,  
   // 
   拖动方向:['all','vertical','horizontal'] 
   
 
    fixarea: 
   null 
     
   // 
   限制在哪个区域拖动,以数组形式提供[minX,maxX,minY,maxY] 
     
    }; })(jQuery); 
 
   // 
    test  
   
 
    $( 
   function 
   (){  
   // 
   限定区域,有回调函数。 
     
    $( 
   ' 
   #dragDiv 
   ' 
   ).dragDrop({fixarea:[ 
   0 
   ,$( 
   ' 
   #dragContainer 
   ' 
   ).width() 
   - 
   50 
   , 
   0 
   ,$( 
   ' 
   #dragContainer 
   ' 
   ).height() 
   - 
   50 
   ],callback: 
   function 
   (params){
 $( 
   ' 
   #span1 
   ' 
   ).text( 
   ' 
   X: 
   ' 
   + 
   params.moveX 
   + 
   ' 
    Y: 
   ' 
   + 
   params.moveY); }});  
   // 
   默认设置 
     
    $( 
   ' 
   #dragDiv1 
   ' 
   ).dragDrop(); });
 
   </ 
   script 
   > 
     
   </ 
   head 
   > 
     
   < 
   body 
   > 
     
   < 
   div  
   id 
   ="dragContainer" 
    style 
   ="position:relative;left:10px;top:10px;border:1px dashed blue;width:500px;height:500px;" 
   > 
   
 
   < 
   div  
   id 
   ="dragDiv" 
    style 
   ="background-color:blue;height:50px;width:50px;" 
   > 
     
   </ 
   div 
   > 
     
   < 
   div  
   id 
   ="dragDiv1" 
    style 
   ="border:1px solid red;height:50px;width:50px;" 
   > 
     
   </ 
   div 
   > 
   
 
   </ 
   div 
   > 
     
   < 
   span  
   id 
   ="span1" 
   ></ 
   span 
   > 
   </ 
   body 
   > 
     
   </ 
   html 
   >