看了那些个框架里关于拖曳方面的例子,一看代码,昏倒,乱得很,有的又只支持IE,ff下根本没用,郁闷之下,决定自己写一个。
  为了在ff下能用,花了点时间,代码如下:
  event.js:
/**
 * 事件处理类
 * @author zxub 2006-06-21
 
*/
var Event=new function()
{
    
this.element=function(_event)
    {
        
return _event.target || _event.srcElement;        
    }
    
    
this.pointerX=function(_event)
    {
        
return _event.pageX || (_event.clientX+(document.documentElement.scrollLeft || document.body.scrollLeft));
    }
    
    
this.pointerY=function(_event)
    {
        
return _event.pageY || (_event.clientY+(document.documentElement.scrollTop || document.body.scrollTop));
    }
    
    
this.isLeftClick=function(_event)
    {
        
return (((_event.which) && (_event.which==1)) || ((_event.button) && (_event.button==1)));
    }
    
    
this.observers=null;
    
    
this.alreadyObserve=function(element,name,observer,useCapture)
    {
        
for (var i=0; i<Event.observers.length; i++)
        {
            
if (Event.observers[i][0]==element && Event.observers[i][1]==name && Event.observers[i][2]==observer)
            {
                
return true;                
            }
        }
        
return false;
    }
    
    
this.unReg=function(element,name,observer,useCapture)
    {
        
for (var i=0; i<Event.observers.length; i++)
        {
            
if (Event.observers[i][0]==element && Event.observers[i][1]==name && Event.observers[i][2]==observer)
            {
                Event.observers[i][
0]=null;
                Event.observers.splice(i,
1);
                
break;
            }
        }
    }
    
    
/**
     * 防止事件传播,进行中止
     
*/
    
this.stopEvent=function(_event)
    {
        
if (_event.preventDefault)
        {
            _event.preventDefault();
            _event.stopPropagation();
        }
        
else
        {
            _event.returnValue 
= false;
            _event.cancelBubble 
= true;
        }
    }
    
    
    
/**
     * 增加事件处理
     * 注意,对于同一个Element,IE和Firefox的处理顺序是相反的,IE用栈的形式,后注册的先执行,而Firefox用队列的形式,先注册先执行
     * 至于useCapture,是当element存在包含关系,事件的处理顺序
     * 处理顺序有2种,capturing和bubbling
     * capturing是从外向内,而bubbling是从内向外
     * IE只支持bubbling,所有useCapture是没有意义的
     * Firefox中,2种都支持,useCapture为false的时候为bubbling,true为capturing,推荐用bubbling
     * 默认useCapture为false
     
*/
    
this.observe=function(element, name, observer, useCapture)
    {
        
if (typeof(element)=="string")
        {
            element
=document.getElementById(element);
        }
        useCapture 
= useCapture || false;
        
if (this.observers==null)
        {
            
this.observers=new Array();
        }        
        
//检查是否注册了同样的事件处理
        if (Event.alreadyObserve(element, name, observer, useCapture)) return;        
        
if (element.addEventListener) //firefox
        {          
            element.addEventListener(name, observer, useCapture);
        }
        
else if (element.attachEvent) //IE
        {
            element.attachEvent(
"on"+name, observer);
        }
        
this.observers.push([element, name, observer, useCapture]);        
    }
    
    
this.stopObserving=function(element, name, observer, useCapture)
    {
        
if (typeof(element)=="string")
        {
            element
=document.getElementById(element);
        }
        useCapture 
= useCapture || false;
        
        
if (element.removeEventListener)
        {
            element.removeEventListener(name, observer, useCapture);
        }
        
else if (element.detachEvent)
        {
            element.detachEvent(
"on"+name, observer);
        }
        Event.unReg(element, name, observer, useCapture);
    }
    
    
this.clearObservers=function()
    {
        
if (Event.observers==nullreturn;
        
for (var i=0;i<Event.observers.length; i++)
        {
            Event.stopObserving.apply(
this, Event.observers[i]);
            Event.observers[i][
0= null;//释放对element的引用
        }
        Event.observers 
= null;
    }
}

if (window.navigator.userAgent.indexOf("MSIE")>=1)
{
    Event.observe(window,'onunload',Event.clearObservers,
false);
}

  position.js:
var Position=new function()
{
    
this.getPosition=function(element)
    {
        
if (element==undefined || element==null || element==""return new Position.instance(0,0,0,0);
        
var offsetTop=element.offsetTop;
        
var offsetLeft=element.offsetLeft;
        
var offsetWidth=element.offsetWidth;
        
var offsetHeight=element.offsetHeight;
        
while (element=element.offsetParent)
        {
            
if (element.style.position=='absolute' || element.style.position=='relative' || (element.style.overflow!='visible' && element.style.overflow!=''))
            {
                
break;
            }
            offsetTop
+=element.offsetTop;
            offsetLeft
+=element.offsetLeft;
        }
        
return new Position.instance(offsetTop,offsetLeft,offsetWidth,offsetHeight);
    }
    
    
this.inside=function(_source,_target)
    {
        
var _tPosition=Position.getPosition(_target);
        
var _sPosition=Position.getPosition(_source);
        
return (_sPosition.minX>=_tPosition.minX && _sPosition.maxX<=_tPosition.maxX && _sPosition.minY>=_tPosition.minY && _sPosition.maxY<=_tPosition.maxY);
    }
    
    
this.outside=function(_source,_target)
    {
        
var _tPosition=Position.getPosition(_target);
        
var _sPosition=Position.getPosition(_source);
        
return (_sPosition.maxX<_tPosition.minX || _sPosition.minX>_tPosition.maxX || _sPosition.minY>_tPosition.maxY || _sPosition.maxY<_tPosition.minY);
    }
}

Position.instance
=function(_top,_left,_width,_height)
{
    
this.top=_top;
    
this.left=_left;
    
this.width=_width;
    
this.height=_height;
    
this.minX=this.left;
    
this.maxX=this.left+this.width;
    
this.minY=this.top;
    
this.maxY=this.top+this.height;
    
this.toString=function()
    {
        
return "top:"+this.top+";left:"+this.left+";width:"+this.width+";height:"+this.height+";xRange:"+this.minX+"-"+this.maxX+";yRange:"+this.minY+"-"+this.maxY;
    }
}

Position.direction
=new function()
{
    
this.up=false;
    
this.down=false;
    
this.left=false;
    
this.rgiht=false;
    
this.lastX=0;
    
this.lastY=0;
    
this.setInitValue=function(_x,_y)
    {
        
this.lastX=_x;
        
this.lastY=_y;
    }
    
    
this.setDirection=function(_cX,_cY)
    {
        
if (_cX==undefined) _cX=Event.pointerX(event);
        
if (_cY==undefined) _cY=Event.pointerY(event);
        
this.up=(_cY<this.lastY);
        
this.down=!this.up;
        
this.left=(_cX<this.lastX);
        
this.right=!this.left;
        
this.setInitValue(_cX,_cY);
    }
    
    
this.toString=function()
    {
        
return "up:"+this.up+";down:"+this.down+";left:"+this.left+";right:"+this.right;
    }
}

  drag.js:
var Drag=new function()
{    
    
this.source=new Array();
    
this.target=new Array();
    
    
this.topDistance=0;
    
this.leftDistance=0;
    
    
this.currentObj=null;
    
    
this.currentContainer=null;
    
    
this.isDragging=false;
    
    
this.addSource=function()
    {
        
for (var i = 0; i < arguments.length; i++)
        {
            
var _element = arguments[i];
            
if (typeof(_element)=="string")
            {
                _element
=document.getElementById(_element);
            }            
            Drag.source.push(
new Drag.sourceObj(_element));            
        }
    }
    
    
this.hasSource=function(_element)
    {
        
for (var i=0; i<Drag.source.length; i++)
        {
            
if (Drag.source[i].element==_element)
            {
                
return true;
            }
        }
        
return false;
    }
    
    
this.addTarget=function(_element)
    {
        
for (var i = 0; i < arguments.length; i++)
        {
            
var _element = arguments[i];
            
if (typeof(_element)=="string")
            {
                _element
=document.getElementById(_element);
            }
            Drag.target.push(
new Drag.targetObj(_element));            
        }
    }
    
    
this.hasTarget=function(_element)
    {
        
for (var i=0; i<Drag.target.length; i++)
        {
            
if (Drag.target[i].element==_element)
            {
                
return true;
            }
        }
        
return false;
    }
    
    
this.start=function(event)
    {
        
if (!Event.isLeftClick(event)) return;
        Drag.currentObj
=Event.element(event);
        
if (Drag.hasSource(Drag.currentObj))
        {
            Drag.currentObj.style.cursor
="move";
            
var p=Position.getPosition(Drag.currentObj);
            
var x=Event.pointerX(event);
            
var y=Event.pointerY(event);
            Position.direction.setInitValue(x,y);            
            Drag.topDistance
=y-p.top;
            Drag.leftDistance
=x-p.left;
            
            DashedDiv.div.style.width
=p.width;
            DashedDiv.div.style.height
=p.height;
            DashedDiv.div.style.display
="";
            
            Drag.currentObj.parentNode.insertBefore(DashedDiv.div,Drag.currentObj);
            
            Drag.currentObj.style.top
=p.top+5;
            Drag.currentObj.style.left
=p.left+5;
            Drag.currentObj.style.position
="absolute";
            
            document.body.appendChild(Drag.currentObj);
            
            Drag.isDragging
=true;
            
            Event.observe(document,
"mousemove",Drag.drag);
            Event.observe(document,
"mouseup",Drag.end);
        }
        
else
        {
            Drag.currentObj
=null;
        }
    }
    
    
this.drag=function(event)
    {
        
if (!Event.isLeftClick(event) || !Drag.isDragging || Drag.currentObj==nullreturn;
        
        
var x=Event.pointerX(event);
        
var y=Event.pointerY(event);
        Position.direction.setDirection(x,y);        
        
        Drag.currentObj.style.top
=y-Drag.topDistance;
        Drag.currentObj.style.left
=x-Drag.leftDistance;
        
if (Drag.currentContainer==null)
        {
            
for (var i=0;i<Drag.target.length;i++)
            {
                
if (Position.inside(Drag.currentObj,Drag.target[i].element))
                {
                    Drag.currentContainer
=Drag.target[i].element;
                    Drag.setDashedDivPosition();
                    
break;                    
                }
            }
        }
        
else
        {
            
if (Position.outside(Drag.currentObj,Drag.currentContainer))
            {
                Drag.currentContainer
=null;
            }
            
else
            {
                Drag.setDashedDivPosition();
            }
        }
    }
    
    
this.end=function(event)
    {
        
if (!Event.isLeftClick(event)) return;
        
if (Drag.currentObj!=null)
        {       
            DashedDiv.div.parentNode.insertBefore(Drag.currentObj,DashedDiv.div);
            DashedDiv.div.style.display
="none";
            
            Drag.currentObj.style.position
="relative";
            Drag.currentObj.style.cursor
="default";
            
            
            Drag.currentObj.style.top
=0;
            Drag.currentObj.style.left
=0;
            
            Drag.currentObj
=null;
            Drag.currentContainer
=null;
            Drag.topDistance
=0;
            Drag.leftDistance
=0;
            
this.isDragging=false;
            
            Position.direction.setInitValue(
0,0);
        }
        
//发送请求保存页面
    }
    
    
this.setDashedDivPosition=function()
    {        
        
if (Position.direction.down)
        {
            
if (DashedDiv.div.parentNode!=Drag.currentContainer)
            {
                Drag.currentContainer.insertBefore(DashedDiv.div,Drag.currentContainer.firstChild)
                
return;
            }
            
var cp=Position.getPosition(Drag.currentObj);
            
var nextNode=Drag.handler.getNextNode(DashedDiv.div);
            
var p=Position.getPosition(nextNode);
            
var node=null;
            
while (nextNode!=null && cp.minY>p.minY+2)
            {
                node
=nextNode;
                nextNode
=Drag.handler.getNextNode(nextNode);
                p
=Position.getPosition(nextNode);
            }
            
if (node!=null)
            {
                
if (node.nextSibling)
                {
                    node.parentNode.insertBefore(DashedDiv.div,node.nextSibling);
                }
                
else
                {
                    node.parentNode.appendChild(DashedDiv.div);
                }
            }
        }
        
else if (Position.direction.up)
        {
            
if (DashedDiv.div.parentNode!=Drag.currentContainer)
            {
                Drag.currentContainer.appendChild(DashedDiv.div);
                
return;
            }
            
var cp=Position.getPosition(Drag.currentObj);
            
var previousNode=Drag.handler.getPreviousNode(DashedDiv.div);
            
var p=Position.getPosition(previousNode);
            
var node=null;
            
while (previousNode!=null && cp.minY<p.minY-2)
            {
                node
=previousNode;
                previousNode
=Drag.handler.getPreviousNode(previousNode);
                p
=Position.getPosition(previousNode);
            }
            
if (node!=null)
            {
                node.parentNode.insertBefore(DashedDiv.div,node);
            }
        }
    }
}

Drag.sourceObj
=function(_element)
{
    
this.element=_element;
    Event.observe(
this.element,"mousedown",Drag.start);    
}

Drag.targetObj
=function(_element)
{
    
this.element=_element;    
}



var DashedDiv=new function()
{
    
this.div=null;
    
this.init=function()
    {
        
if (this.div==null)
        {
            
this.div=document.createElement("div");
            
this.div.id="dashed";
            
this.div.style.cssText="border:1px dashed red;position:relative;cursor:move;filter:alpha(opacity=60);-moz-opacity:0.6;display:none";
            document.body.appendChild(
this.div);
        }
    }
    
this.init();
}

//为不支持swapNode的浏览添加方法
if (window.Node)
{
    Node.prototype.swapNode
=function(node)//由于在ff下测试出了错,所以没用
    {     
        
var nextSibling=this.nextSibling;
        
var parentNode=this.parentNode;
        node.parentNode.replaceChild(
this,node);
        parentNode.insertBefore(node,nextSibling);   
    }
}

Drag.handler
=new function()
{
    
this.swap=function(_node1,_node2)
    {
        _node1.swapNode(_node2);
    }
    
    
this.getNextNode=function(_node)
    {
        
var sibling = _node.nextSibling;
        
while (sibling != null)
        {
            
if (sibling.nodeName==_node.nodeName) return sibling;
            sibling 
= sibling.nextSibling;
        }
        
return null;
    }
    
    
this.getPreviousNode=function(_node)
    {
        
var sibling = _node.previousSibling;
        
while (sibling != null)
        {
            
if (sibling.nodeName==_node.nodeName) return sibling;
            sibling 
= sibling.previousSibling;
        }
        
return null;
    }
}

  测试页面:
<html>
<head>
<title>测试</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
<style type="text/css">
<!--
body,tr,td 
{ font-size: 12px;}
div 
{margin:5 5 5 5}
-->
</style>
</head>
<body>
<script type="text/javascript" src="event.js"></script>
<script type="text/javascript" src="position.js"></script>
<script type="text/javascript" src="drag.js"></script>
<div id="t1" style="width:200px;height:50px;border:1px solid black">1</div>
<div id="t2" style="width:200px;height:100px;border:1px solid black">2</div>
<div id="t3" style="width:500px;height:300px;border:1px solid black;padding:5 5 5 5">    
    
<div id="t5" style="width:200px;height:50px;border:1px solid black">5</div>
    
<div id="t6" style="width:200px;height:50px;border:1px solid black">6</div>
</div>
<div id="t4" style="width:500px;height:200px;border:1px solid black;padding:5 5 5 5"></div>
<div id="info"></div>
<script type="text/javascript">
Drag.addSource(
"t1","t2","t5","t6");
Drag.addTarget(
"t3","t4");
</script>
</body>
</html>

  关于位置保存,以后再加上来。
  源码下载: drag.rar
 posted on 2006-06-28 22:22  往事如风  阅读(2044)  评论(3编辑  收藏  举报