您的位置:首页 > 运维架构

Div的drag-drop实践结果【原创】

2006-06-28 22:22 225 查看
  看了那些个框架里关于拖曳方面的例子,一看代码,昏倒,乱得很,有的又只支持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==null) return;
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==null) return;

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: