注释很全:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style>
*{margin:0; padding:0;}
#main{width:1000px; height:600px; position:relative; background:#CCC; margin:20px auto;}
.box{ width: 100px;height: 100px;position: absolute;font-size: 50px;text-align: center;line-height: 100px;border-radius: 50%;cursor: pointer;}
.one{left:50px; top:50px; background:red; }
.two{right:50px; top:50px; background:green;}
.three{left:50px; bottom:50px; background:blue;}
.four{right:50px; bottom:50px; background:yellow;}
</style>
<script>
/**
*实现过程原理:根据移动框在移动过程中时时的位置记录,来判断他是否进入到其他静态框的区域,如果进入则互相交换最原始的位置
*注意1:判断进入区域的标准 移动左>静框右,移动右<静框左,移动上>静框下,移动下<静框上,只要满足一个都说明没有进来
*注意2:释放鼠标如果没有进入任何区域要把移动框放回原位置
*/
window.onload=function()
{
var oDiv=document.getElementById('main'); //获取最外层的div标签,算是父标签,后期用来判断移动框是否拉出了可视区域
var aDiv=oDiv.getElementsByTagName('div'); //获取移动框的div标签,以数组的方式存储这些标签
var a=10;
for(var i=0;i<aDiv.length;i++)
{
aDiv[i].index=i;
aDiv[i].onmousedown=function(ev) //鼠标按下动作开始
{
var result={}; //用来存放标识:判断移动框移动到了其他剩余框的哪个框的区域,进入的区域为true,其他为false,座位后期换位的标识
var arr=[]; //用来存放四个移动框的位置,外层采用数组,内层采用对象的方式
var Num=0; //用来存放当前移动框的索引标识
var oEvent=ev||event; //获取鼠标时间对象
var DownX=this.offsetLeft; //获取移动框最原始的位置,距离左边的距离
var DownY=this.offsetTop; //获取移动框距离上面的距离
var disX=oEvent.clientX-this.offsetLeft; //获取鼠标点击的位置相对移动框的左边的距离
var disY=oEvent.clientY-this.offsetTop; //获取鼠标点击的位置相对移动框的左边的距离
for(var i=0;i<aDiv.length;i++) //把所有移动框最原始的坐标距离存放到arr的数组中区,作为后期判断的依据
{
var json={
l:aDiv[i].offsetLeft,
r:aDiv[i].offsetLeft+aDiv[i].offsetWidth,
t:aDiv[i].offsetTop,
b:aDiv[i].offsetTop+aDiv[i].offsetHeight
}
arr.push(json)
}
Num=this.index; //num是当前移动框的索引值,后期的aDiv[Num]就是当前移动的移动框标签对象
document.onmousemove=function(ev) //鼠标移动事件
{
var oEvent=ev||event; //获取当前的鼠标事件,用于后期来获取和事件相关的信息
aDiv[Num].style.left=oEvent.clientX-disX+'px'; //移动过程中设置移动框的位置
aDiv[Num].style.top=oEvent.clientY-disY+'px';
//如果移动框向左移动过了边框,那么设置它的左边距为0,下同,如果右边超出了则设置左边距为外框的宽度减去移动框的宽度,确保移动框在可视区域内
if(aDiv[Num].offsetLeft<0)
{
aDiv[Num].style.left=0;
}
else if(aDiv[Num].offsetLeft>oDiv.clientWidth-aDiv[Num].clientWidth)
{
aDiv[Num].style.left=oDiv.clientWidth-aDiv[Num].clientWidth+'px';
}
//同上,用来判断移动框是否向上向下移动出了可视区域
if(aDiv[Num].offsetTop<0)
{
aDiv[Num].style.top=0;
}
else if(aDiv[Num].offsetTop>oDiv.clientHeight-aDiv[Num].clientHeight)
{
aDiv[Num].style.top=oDiv.clientHeight-aDiv[Num].clientHeight+'px';
}
//获取当前移动框的上下左右的位置,用来判断是否移动到了其他框的区域内
l=aDiv[Num].offsetLeft;
r=aDiv[Num].offsetLeft+aDiv[Num].offsetWidth;
t=aDiv[Num].offsetTop;
b=aDiv[Num].offsetTop+aDiv[Num].offsetHeight;
for(var i=0;i<arr.length;i++)
{
if(i==Num) //在进行是否移入其他框区域内的时候,剔除移动框本身,且把他的标识设置为flase,不能最为后期的交换框来用
{
result[i] = false;
continue;
}
else
{ //如果移动框没有进入当前框的区域,判断标准:移动左>框右,移动右<框左,移动上>框下,移动下<框上,同时设置标识为false
if(l>arr[i].r || r<arr[i].l || t>arr[i].b || b<arr[i].t)
{
result[i] = false;
}
else
{
result[i] = true; //移动框进入了当前框的区域,设置该索引下的标识为true
//当前框背景虚化,加一点透明,用来显示移动框进入了当前框的区域,其他框都正常显示
for(var c=0;c<aDiv.length;c++)
{
aDiv[c].style.opacity='1';/*非IE*/
aDiv[c].style.filter='alpha(opacity='+100+')';/*IE*/
}
aDiv[i].style.opacity='0.3';/*非IE*/
aDiv[i].style.filter='alpha(opacity='+30+')';/*IE*/
break;
}
}
}
};
document.onmouseup=function()
{
// 鼠标一旦抬起,其他的鼠标事件都终止
document.onmousemove=null;
document.onmouseup=null;
//所有虚化都去掉,百分百显示
for(var c=0;c<aDiv.length;c++)
{
aDiv[c].style.opacity='1';/*非IE*/
aDiv[c].style.filter='alpha(opacity='+100+')';/*IE*/
}
var flag = true; //标志位,用来判断移动框是否进入到其他框的区域,如果没有则让移动框回到初始的位置
for(var i in result)
{
if(result[i]) //如果框的标志位里面存在true这一值,说明移动框移动进入了i索引下的框的区域
{
aDiv[Num].style.left=aDiv[i].offsetLeft+'px'; //彼此交换位置,交换最初的位置
aDiv[Num].style.top=aDiv[i].offsetTop+'px';
aDiv[i].style.left=DownX+'px';
aDiv[i].style.top=DownY+'px';
flag = false; //标志位为false,代表有交换的框存在
}
}
if(flag) //flag为true,移动框没有移入到任何框的区域,移动框回到原始位置
{
aDiv[Num].style.left=DownX+'px';
aDiv[Num].style.top=DownY+'px';
}
};
return false; //阻止事件继续向上层冒泡
};
}
};
</script>
</head>
<body>
<div id="main">
<div class="box one">1</div>
<div class="box two">2</div>
<div class="box three">3</div>
<div class="box four">4</div>
</div>
</body>
</html>