一个简单的拖拽研究了快一周,恶心的我呦...好在终于整明白了,下面和大家一起交流下。拖拽原理:
鼠标按下时,记录当前鼠标和拖动层的坐标,并且拖动状态设为可拖动;
鼠标移动时,判断拖动状态,如果可拖动,那么根据当前的鼠标坐标以及鼠标按下时记录的初始坐标,计算出拖动层的位置,实行拖动;
鼠标弹起时,将拖动状态改为不可拖动。遇到的问题:
1.移动较快时,拖拽失效;
2.火狐中,拖拽动作与浏览器的某些功能有冲突,导致动作不流畅或失效;下面我一步步的把我的修改过程贴出来,大家一起交流啊~

解决方案 »

  1.   

    一、最基本的拖动能实现拖动,但是速度稍快点就会出问题。
    另外:Y0=parseInt(moveObj.style.top+0);//?不清楚为什么一定要+0
    <html>
    <head>
    <style>
    #move{cursor:move; position:absolute; width:100px; height:100px; background:green;}
    </style><script language="javascript">
    //载入完成时执行
    window.onload=function(){
    var moveable=false;//初始化是否可拖动
    var X0,Y0,eX0,eY0;//声明变量
    var moveObj=document.getElementById('move');//获取到拖动对象
    //鼠标按下
    moveObj.onmousedown=function(e){//e只是一个参数,表示一个事件,名称可随便起
    e=e||event;//鼠标事件在火狐里存在内存中可供函数直接调用;在IE里存放在window对象中,即window.event
    eX0= e.clientX;//记录下拖动对象的坐标X0,Y0
    eY0= e.clientY;
    X0=parseInt(moveObj.style.left+0);//记录下mousedown事件发生时,鼠标的坐标eX0,eY0
    Y0=parseInt(moveObj.style.top+0);//?不清楚为什么一定要+0
    moveable=true;//拖动状态改为可拖动
    }
    //鼠标移动
    moveObj.onmousemove=function(e){
    if (moveable==true)
    {
    e=e||event;
    var eX1= e.clientX;
    var eY1= e.clientY;
    moveObj.style.left=X0+eX1-eX0+"px";//由鼠标刚按下时记录的各个初始值,计算当前拖动对象的坐标
    moveObj.style.top=Y0+eY1-eY0+"px";
    }
    }
    //鼠标弹起
    moveObj.onmouseup=function(e){
    if(moveable) moveable=false;//状态改为不可拖动
    }
    }

    </script>
    </head><body>
    <div id="move"></div>
    </body>
    </html>
      

  2.   

    二、解决拖拽速度较快时的bug不知道上一种,先获取拖动对象,根据对象的事件来拖动的方式有什么错误的地方,但是它在拖拽较快的时候确实有问题。
    百度了下,还有另一种方式,就是把事件全加在document上,然后判断事件目标是否为要拖拽的元素。我感觉应该是这种方式浏览器可以及时地感应到任何一个位置发生的事件,不至于鼠标移得快了就跟不上了...(菜鸟,欢迎交流~)
    <html>
    <head>
    <style>
    .move{cursor:move; position:absolute; width:100px; height:100px; background:green;}
    </style><script language="javascript">
    var X0,Y0;
    var dragAble=false;
    var dragObj;
    document.onmousedown=function(e){
    var oDragHandle=e? e.target:event.srcElement;
    if(oDragHandle.className=='move') 
    {
    dragObj=oDragHandle;
    e=e||event;
    eX0= e.clientX;
    eY0= e.clientY;
    X0=parseInt(dragObj.style.left+0);
    Y0=parseInt(dragObj.style.top+0);
    dragAble=true;
    }
    }
    document.onmousemove=function(e){
    if(dragObj)
    {
    e=e||event;
    var eX1= e.clientX;
    var eY1= e.clientY;
    dragObj.style.left=X0+eX1-eX0+"px";
    dragObj.style.top=Y0+eY1-eY0+"px";
    }
    }document.onmouseup=function(e){
    if(dragObj) dragObj=null;
    }</script>
    </head><body>
    <div class="move"></div>
    </body>
    </html>
      

  3.   

    三、完美兼容火狐火狐不知道是具体是怎么回事,拖拽的时候,它会有个虚影,然后mouseup事件响应也有很严重的bug,很影响效果。解决办法有两个:
    1.在拖动块里加上内容,不论是空标签还是嵌套别的东西,只要是有内容,就不会出现那个虚影的问题;
    2.样式控制,禁止选中。-moz-user-select:none;/*火狐禁止选中*/
    下面代码中采用的第二种办法。
    <html>
    <head>
    <style>
    .move{cursor:move; position:absolute; width:100px; height:100px; background:green;-moz-user-select:none;/*火狐禁止选中*/}
    </style>
    <script language="javascript">
    var X0,Y0;
    var dragAble=false;
    var dragObj;
    document.onmousedown=function(e){
    var oDragHandle=e? e.target:event.srcElement;
    if(oDragHandle.className=='move') 
    {
    dragObj=oDragHandle;
    e=e||event;
    eX0= e.clientX;
    eY0= e.clientY;
    X0=parseInt(dragObj.style.left+0);
    Y0=parseInt(dragObj.style.top+0);
    dragAble=true;
    }
    }
    document.onmousemove=function(e){
    if(dragObj)
    {
    e=e||event;
    var eX1= e.clientX;
    var eY1= e.clientY;
    dragObj.style.left=X0+eX1-eX0+"px";
    dragObj.style.top=Y0+eY1-eY0+"px";
    }
    }
    document.onmouseup=function(e){
    if(dragObj) dragObj=null;
    }</script>
    </head><body>
    <div class="move"><!--<br/>如果样式规定里此div可选,并且没有内容的话,火狐会有bug--></div>
    </body>
    </html>
      

  4.   

    嗯,同意,我就是自己没写出来,百度的别人的,然后整合了一下。
    短一点的话效率我不大清楚,不过对初学者来说肯定是容易理解点儿。
    然后那个拖拽的实现方式上。我觉得思路应该只有这个思路了。还有那个+0,我觉得很别扭,明明parseInt()已经转成整形了,为什么要在里面写个+0呢?
      

  5.   

     你必须要用到 setCapture 和releaseCapture没用到这个的话,你如果拖动太快,该层会失去焦点
      

  6.   

    +0应该如楼上所说是转换为数字类型,你可以使用函数parseint、pasefloat或Numeric来解决这个问题,但是不知道效率那个更高点,楼主如果感兴趣可以查查哟
      

  7.   

    四、添加事件监听
    这两天找到了一个更正规的事件处理方式,就是IE:attachEvent(),w3c:addEventListener()
    例:window.attachEvent ? obj.attachEvent("onmousedown", Foo): obj.addEventListener("mousedown", Foo, false);添加了事件监听之后,我很吃惊的发现在IE里也可以像火狐那样支持“以传参数的形式获取事件对象了”,信不信大家可以自己试一下,下面是代码。<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html>
    <head>
    <style>
    .move{cursor:move; position:absolute; width:100px; height:100px; background:green;-moz-user-select:none;/*火狐禁止选中*/}
    </style>
    <script language="javascript">
    var X0,Y0,eX0,eY0;
    var dragAble=false;
    var dragObj;
    var ie = (document.all) ? true : false;//是否为IEfunction dragStart(e){//现在参数e在IE里也是是直接可以供函数使用的,比如第16行。
    var oDragHandle;
    if(ie){
    oDragHandle = e.srcElement;
    }else{
    oDragHandle = e.target;
    }
    if(oDragHandle.className=='move') 
    {
    dragObj=oDragHandle;
    eX0= e.clientX;
    eY0= e.clientY;
    X0=parseInt(dragObj.style.left+0);
    Y0=parseInt(dragObj.style.top+0);
    dragAble=true;
    }
    }
    //拖拽
    function drag(e){
    if(dragAble)
    {
    var eX1= e.clientX;
    var eY1= e.clientY;
    dragObj.style.left=X0+eX1-eX0+"px";
    dragObj.style.top=Y0+eY1-eY0+"px";
    }
    }
    //停止拖拽
    function dragEnd(){
    dragAble=false;
    }
    //事件监听浏览器兼容
    function addListener(element,eName,fn){
        if(ie){// ie 
    element.attachEvent("on"+eName,fn);
        }else {// firefox  , w3c
    element.addEventListener(eName,fn,false);
        }
    }//添加事件监听
    window.onload = function(){
    addListener(document,"mousedown",dragStart);//鼠标按下开始拖拽
    addListener(document,"mousemove",drag);//拖拽
    addListener(document,"mouseup",dragEnd);//弹起停止拖拽
    }
    //注:添加了事件监听之后,IE里也可以像火狐里那样直接拿事件对象当函数的参数来用了,不必再window.event。
    //但是不大清楚这是为什么,或者是说我还有什么地方理解错了,求交流。QQ:1140215489
    </script>
    </head><body>
    <div class="move"><!--<br/>如果样式规定里此div可选,并且没有内容的话,火狐会有bug--></div>
    <div class="move" style="background:blue;left:200px"></div>
    </body>
    </html>
      

  8.   

    五、获取当前渲染样式值上一次发的代码里还有不正确的地方:
            X0=parseInt(dragObj.style.left+0);    
            Y0=parseInt(dragObj.style.top+0);
    --如果初始没有设置div的top值,浏览器dragObj.style.left是个空字符串,+0是为了让X0初始为0;如果拖动块不在左上角就不能这么写了,得先设置上top,left值,因为Obj.style.left只能获取行内样式,所以得换一种方法来获取当前的样式值。
    //获取当前渲染样式
    function getNowStyle(element,styleName){
    var nowValue=parseInt(ie?element.currentStyle[styleName]:window.getComputedStyle(element,null)[styleName]);
    return nowValue;
    }<!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" />
    <style>
    .move{
    cursor:move;
    position:absolute;
    top:10px;/*必须要设置,不然在IE里获取的.top为auto,无法进行算术运算*/
    left:400px;
    width:100px;
    height:100px;
    background:green;
    -moz-user-select:none;/*火狐禁止选中*/
    }
    .food{background:blue;width:100px;height:100px;}
    </style>
    <script language="javascript">
    var X0,Y0,eX0,eY0;
    var dragAble=false;
    var dragObj;
    var ie = (document.all) ? true : false;//是否为IE//开始拖拽
    function dragStart(e){
    var oDragHandle;
    if(ie){
    oDragHandle = e.srcElement;
    }else{
    oDragHandle = e.target;
    }
    if(oDragHandle.className=='move'){
    dragObj=oDragHandle;
    eX0= e.clientX;
    eY0= e.clientY;
    X0=getNowStyle(dragObj,"left");//获取当前样式值
    Y0=getNowStyle(dragObj,"top");
    show(X0,Y0);
    dragAble=true;
    }
    }
    //拖拽
    function drag(e){
    if(dragAble){
    var eX1= e.clientX;
    var eY1= e.clientY;
    dragObj.style.left=X0+eX1-eX0+"px";
    dragObj.style.top=Y0+eY1-eY0+"px";
    }
    }
    //停止拖拽
    function dragEnd(){
    dragAble=false;
    }
    //事件监听浏览器兼容
    function addListener(element,eName,fn){
        if(ie){// ie 
    element.attachEvent("on"+eName,fn);
        }else {// firefox  , w3c
    element.addEventListener(eName,fn,false);
        }
    }
    //添加事件监听
    window.onload = function(){
    addListener(document,"mousedown",dragStart);//鼠标按下开始拖拽
    addListener(document,"mousemove",drag);//拖拽
    addListener(document,"mouseup",dragEnd);//弹起停止拖拽
    }
    //当前渲染样式
    function getNowStyle(element,styleName){
    var nowValue=parseInt(ie?element.currentStyle[styleName]:window.getComputedStyle(element,null)[styleName]);
    return nowValue;
    }</script>
    </head>
    <body>
    <div class="move"><!--<br/>如果样式规定里此div可选,并且没有内容的话,火狐会有bug--></div>
    <div class="food"></div>
    </body>
    </html>
      

  9.   

    1.从event.screenX or screenY 取值是最快的.
    2.可以添加一个卡喉函数来降低CPU损耗..
    ---仅供参考---<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <HTML>
     <HEAD>
      <TITLE> New Document </TITLE>
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></HEAD> <BODY style="height:800px;">
    <div id="testDiv" style="width:200px; height:200px; background:#f00; position:absolute; cursor:move"></div>
    <script type="text/javascript">
    var start =
    (function(){
    var i, // count
    o, // HTML DOM
    x,y;

    function moving(e)
    {
    if(i++^6)//like if(!(i++===6))
    return;
    o.style.left=(e.screenX-x)+'px';
    o.style.top=(e.screenY-y)+'px';
    i=0;
    } function end(e)
    {
    if(window.addEventListener){
    window.document.removeEventListener('mousemove',moving,false);
    document.removeEventListener('mouseup',arguments.callee,false);
    }else{
    window.document.detachEvent('onmousemove',moving);
    window.document.detachEvent('onmouseup',arguments.callee);
    }

    window.document.body.focus() // ff 3.0
    }

    return function(e,d)
    {
    i = 0;
    x = e.screenX-d.offsetLeft;
    y = e.screenY-d.offsetTop;
    o = d;

    if(window.addEventListener){
    window.document.addEventListener('mousemove',moving,false)
    window.document.addEventListener('mouseup',end,false)
    }else{
    window.document.attachEvent('onmousemove',moving)
       window.document.attachEvent('onmouseup',end)
    }
    }
    })();


    document.getElementById('testDiv').onmousedown=function(e){
    e=e || event;
    start(e,this);
    e.cancelBubble=true;
    return false;
    }
    </script>
     </BODY>
    </HTML>
      

  10.   


    //注:添加了事件监听之后,IE里也可以像火狐里那样直接拿事件对象当函数的参数来用了,不必再window.event。
    //但是不大清楚这是为什么,或者是说我还有什么地方理解错了,求交流。QQ:1140215489求高手解答
      

  11.   

    Y0=parseInt(moveObj.style.top+0);//?不清楚为什么一定要+0   这个0不用加吧?http://www.cnblogs.com/NNUF/archive/2012/04/02/2430132.html
      

  12.   

    Y0=parseInt(moveObj.style.top+0);//?不清楚为什么一定要+0
    这里面的0可以不用添加的吧,获取的TOP值本生就是带单位的字符串,加个0没用吧
    http://www.cnblogs.com/NNUF/archive/2012/04/02/2430132.html
      

  13.   


    <iframe style="width: 100%; height: 300px" src="http://jsfiddle.net/jikeytang/yKeAk/embedded/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
      

  14.   

    现在jquery不是出了一个可以拖拽的控件么?一句代码就可以搞定,只要引用js代码就好了。