zoukankan      html  css  js  c++  java
  • js拖拽效果 javascript实现将元素拖拽如某容器效果demo

    拖拽效果demo以及文档说明

    Demo效果

    View Code
    <!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>无标题文档</title>
    <script type="text/javascript">
    /*************************************************c插件定义部分******************************************************/
    var Drag = (function () {
        var opts={container:"",drag_items:"",state:"outer" ,setContainerStyle:true ,moveInto:function(){},moveOut:function(){},endInto:function(){}},//默认参数,全局的  state:inner outer center 标示拖拽对象是碰触目标触发还是完全进入目标再触发
            curDrag,
            //以下为私有方法
            getPosition=function(elem){
                if ( !elem ) return {left:0, top:0};  
                var top = 0, left = 0;  
                if ( "getBoundingClientRect" in document.documentElement ){  
                    //jquery方法  
                    var box = elem.getBoundingClientRect(),   
                    doc = elem.ownerDocument,   
                    body = doc.body,   
                    docElem = doc.documentElement,  
                    clientTop = docElem.clientTop || body.clientTop || 0,   
                    clientLeft = docElem.clientLeft || body.clientLeft || 0,  
                    top  = box.top  + (self.pageYOffset || docElem && docElem.scrollTop  || body.scrollTop ) - clientTop,  
                    left = box.left + (self.pageXOffset || docElem && docElem.scrollLeft || body.scrollLeft) - clientLeft;  
                }else{  
                    do{  
                        top += elem.offsetTop || 0;  
                        left += elem.offsetLeft || 0;  
                        elem = elem.offsetParent;  
                    } while (elem);  
              }  
                return {left:left, top:top};      
            },
            
            isJoinToBox=function(curDrag){
                var extendX,
                    extendY,
                    drag_left = parseInt(curDrag.style.left),
                    drag_top = parseInt(curDrag.style.top),
                    box_position = getPosition(opts.container),
                    box_top = box_position.top,
                    box_left = box_position.left,
                    box_bottom = opts.container.offsetHeight + box_top,
                    box_right = opts.container.offsetWidth + box_left;
                    
                    
                switch(opts.state)
                {
                    case "outer":
                                extendX = curDrag.offsetWidth;
                                extendY = curDrag.offsetHeight;                           
                                break;
                    case "inner":
                                extendX=0;
                                extendY=0;
                                break;
                    case "center":
                                extendX = parseInt(curDrag.offsetWidth/2);
                                extendY = parseInt(curDrag.offsetHeight/2);
                                break;
                    default:
                                extendX = curDrag.offsetWidth;
                                extendY = curDrag.offsetHeight;
                                
                }
                return ((drag_left >= box_left-extendX && drag_left <= box_right) &&
                        (drag_top >= box_top-extendY && drag_top <= box_bottom));
            },
            
            start=function(e){
                window.getSelection().removeAllRanges();
                var oldNode = e.target,
                    newNode,
                    top = getPosition(oldNode).top,
                    left = getPosition(oldNode).left;
                    
                if("true" === oldNode.getAttribute("drag"))
                {
                    newNode = oldNode.cloneNode(true);
                    newNode.style.cssText = "z-index:1;background:red;position:absolute; top:"+top+"px;left:"+left+"px";
                    oldNode.parentNode.appendChild(newNode);
                    curDrag = newNode;
                }
            },
            
            move=function(e){
                window.getSelection ? window.getSelection().removeAllRanges():document.selection.empty();
                if(curDrag){
    
                    curDrag.style.top = e.pageY + "px";
                    curDrag.style.left = e.pageX + "px";
                    if(opts.setContainerStyle){
                        if(isJoinToBox(curDrag))
                        {
                            opts.moveInto();
                        }
                        else{
                            opts.moveOut();
                        }
                    }
                }
            },
            
            end=function(e){
                window.getSelection ? window.getSelection().removeAllRanges():document.selection.empty();
                if(curDrag){
                    if(isJoinToBox(curDrag)){
                        opts.endInto(curDrag.cloneNode(true));
                    }
                        
                    if(opts.setContainerStyle){
                        opts.moveOut();
                    }
                    curDrag.parentNode.removeChild(curDrag);
                    curDrag = null;
                }
            },
            
            touchHandler=function(event){        
                var touches=event.changedTouches,
                    touchObj=touches[0],
                    type,
                    simulatedEvent ;
                    
                switch(event.type){
                    case "touchstart":
                         type="mousedown";
                         break;
                    case "touchmove":
                         type="mousemove";
                         break;     
                    case "touchend":
                         type="mouseup";
                         break;
                    default:
                         return;
                
                }
                simulatedEvent=document.createEvent("MouseEvent");
                simulatedEvent.initMouseEventype(type, true, true, window, 1,
                                                first.screenX,first.screenY,
                                                first.clientX, first.clientY,
                                                false,false, false, false, 0, null); 
                
                touchObj.target.dispathEvent(simulatedEvent);
                event.preventDefault();
            },
            
            init=function (option) { 
                for(prop in option) opts[prop]=option[prop];
                //alert(opts.container);
                //初始化事件
                    //如果是移动设备,我们就用事件模拟触发鼠标事件
                    opts.drag_items.addEventListener("touchstart", touchHandler, true);
                    opts.drag_items.addEventListener("touchmove", touchHandler, true);
                    opts.drag_items.addEventListener("touchend", touchHandler, true);
                //监听鼠标事件
                opts.drag_items.addEventListener("mousedown", start, true);
                document.addEventListener("mousemove", move, true);
                document.addEventListener("mouseup", end, true);
                   
            };
        // 暴露公开的成员
        return{
            init: init        
        }
    }());
    
    
    
    
    
    </script>
    </head>
    <style type="text/css">
    span{display:block; 50px; height:50px; background:#dedede; border:1px solid #333; float:left}
    #container{margin:auto;padding:10px;background:#dedede; 380px; height:150px; border:5px solid #777; }
    #container li{50px; height:50px; border:1px dashed #777; float:left; margin:10px 0 0 10px; list-style-type:none;}
    #dragItems{margin:auto; 480px;}
    </style>
    <body style="text-align:center;-webkit-user-select:none;">
    将以下小方格拖入上面的容器内:<br />
    注: id="dragItems"下面的子元素设置 drag="true"属性的才可以拖动<br /><br /><br />
    <ul id="container">
        <li></li><li></li><li></li><li></li><li></li><li></li>
        <li></li><li></li><li></li><li></li><li></li><li></li>
    </ul>
    <br />
    <br />
    <br />
    <br />
    <div id="dragItems"><span drag="true">111</span><span drag="true">222</span><span drag="true">333</span><span drag="true">444</span><span drag="true">555</span><span drag="true">666</span><span drag="true">777</span><span drag="true">888</span><span drag="true">999</span></div>
    
    
    </body>
    </html>
    <script type="text/javascript">
    
    //*******************************************************调用部分**************************************************
    
    var c=document.getElementById("container"),//需要拖入的容器id
        d=document.getElementById("dragItems");//被拖动的元素列表
    Drag.init({
        container : c,
        drag_items : d ,
        state : "outer",//可以设置层outer(拖动元素外边挨着容器就触发),inner(拖动元素全部进入容器才触发),center (拖动元素一半进入容器时触发) 
        moveInto : function(){//当元素被拖入容器内时触发(mousemove时鼠标左键按下状态)
            c.style.border = "5px dashed #ccc";
        },
        moveOut : function(){//当元素被拖出容器时触发(mousemove时鼠标左键按下状态)
            c.style.border = "5px solid #777";
        },
        endInto : function(dragEle){//当元素被拖进容器后触发(mouseup 鼠标抬起)
            var elems=c.getElementsByTagName("li");
            for(var i=0,len=elems.length; i<len ;i++)
            {
                if(elems[i].innerHTML == "")
                {
                    elems[i].appendChild(dragEle);
                    dragEle.style.position="";
                    break;
                }
                if(i == len-1) alert("fulled");
            }
        }
    });
    
    </script>

    JavaScript 拖放效果相关技术说明

     

    【触发对象】

     

    触发对象是用来触发拖放程序的,程序中通过Handle属性设置。有的时候不需要整个拖放对象都用来触发,这时就需要触发对象了。
    使用了触发对象后,进行移动的还是拖放对象,只是用触发对象来触发拖放(一般的使用是把触发对象放到拖放对象里面)。
    ps:触发对象的另一个用法是通过设置相同的Handle,实现一个触发对象同时拖放多个拖放对象。

     

    【范围限制】

     

    要设置范围限制必须先把Limit设为true。范围限制分两种,分别是固定范围和容器范围限制,主要在Move程序中设置。
    原理是当比较的值超过范围时,修正lefttop要设置的值使拖放对象能保持在设置的范围内。

     

    【取消默认动作】

     

    对选择状态的文本内容、连接和图片等进行拖放操作会触发系统的默认动作,例如ie中拖动图片鼠标会变成禁止操作状态,这样会导致这个拖放程序执行失败。

     

    不过ie在设置了setCapture之后,通过用户界面用鼠标进行拖放操作和内容选择都会被禁止。
    意思就是setCapture之后就不能对文档内容进行拖放和选择,注意这里的拖放是指系统的默认动作,例如ondragstart就不会被触发。
    不过如果setCapture的参数是false的话,容器内的对象还是可以触发事件的(具体看鼠标捕获部分),所以setCapture的参数要设成true或保留默认值。

     

    ff的鼠标捕获没有这个功能,但可以用preventDefault来取消事件的默认动作来解决:

     

    oEvent.preventDefault();

     


    ps:据说使用preventDefault会出现mouseup丢失的情况,但我在ff3中测试没有发现,如果各位发现任何mouseup丢失的情况,务必告诉我啊。

     

    【清除选择】

     

    ie在设置setCapture之后内容选择都会被禁止,但也因此不会清除在设置之前就已经选择的内容,而且设置之后也能通过其他方式选择内容,
    例如用ctrl+a来选择内容。
    psonkeydownonkeyuponkeypress事件不会受到鼠标捕获影响。
    ffmousedown时就能清除原来选择的内容,但拖动鼠标,ctrl+a时还是会继续选择内容。
    不过在取消了系统默认动作之后,这样的选择并不会对拖放操作造成影响,这里设置主要还是为了更好的体验。

     

    以前我用禁止拖放对象被选择的方法来达到目的,即ie中设置拖放对象的onselectstart返回false,在ff中设置样式MozUserSelect(css:-moz-user-select)none
    但这种方法只能禁止拖放对象本身被选择,后来找到个更好的方法清除选择,不但不影响拖放对象的选择效果,还能对整个文档进行清除:
    ie:document.selection.empty()
    ff:window.getSelection().removeAllRanges()
    为了防止在拖放过程中选择内容,所以把它放到Move程序中,下面是兼容的写法:

     

    window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

     


    这里说说ff下有一个比较奇怪的现象,在SimpleDrag中第一次拖放没有问题,但第二次拖放时鼠标就会显示禁止操作的样式(拖动失败)。
    我发现如果在Start程序中阻止默认动作(preventDefault)或清除选择(window.getSelection().removeAllRanges())就能正常了。
    所以我估计是在点击事件后,拖放对象已经默认设置成选择状态了(虽然看起来不是),再拖动时就触发了系统的默认拖动事件。
    为了支持推断,我在html插入一段文本,然后在每一次拖放之后选择一下那段文本(间接取消拖放对象的选择),那就能正常了。
    不过暂时还没找到官方说明,所以还不能下结论。

     

  • 相关阅读:
    跟我学Makefile(七)
    C++单例模式
    乘法逆元及求法
    推荐几个jetbrains全家桶好用的插件,同时作为备忘
    win32 获取本机网卡信息(MAC地址,IP地址等)
    centos7 安装 mysql-python时 报错 EnvironmentError: mysql_config not found
    VS2013 中使用 CxImage 库时用Unicode编码时出现链接错误
    剑指offer-二叉搜索树的后序遍历序列
    剑指offer-顺时针打印矩阵
    剑指offer-二叉树的镜像
  • 原文地址:https://www.cnblogs.com/gaoxue/p/drag.html
Copyright © 2011-2022 走看看