<!doctype html>
<html lang=”en”>
 <head>
 <meta charset=”UTF-8″>
 <meta name=”Generator” content=”EditPlus®”>
 <meta name=”Author” content=””>
 <meta name=”Keywords” content=””>
 <meta name=”Description” content=””>
 <title>图片拖拽</title>
 <style type=”text/css”>
 body,ul{
 margin:0px;
 padding:0px;
 }
 .box{
 position:relative;
 width:380px;
 height:380px;
 margin:100px auto;
 border:1px solid black;
 }
 .box ul li{
 margin:20px 0 0 20px;
 width:100px;
 height:100px;
 list-style:none;
 float:left;
 }
 .box ul li img{
 display:inline-block;
 }
 </style>
 </head>
 <body>
<div class=”box”>
 <ul class=”imgWrapper”>
 <li><img src=”1.jpg” alt=”” width=”100px” height=”100px” /></li>
 <li><img src=”2.jpg” alt=”” width=”100px” height=”100px” /></li>
 <li><img src=”3.jpg” alt=”” width=”100px” height=”100px” /></li>
 <li><img src=”4.jpg” alt=”” width=”100px” height=”100px” /></li>
 <li><img src=”5.jpg” alt=”” width=”100px” height=”100px” /></li>
 <li><img src=”6.jpg” alt=”” width=”100px” height=”100px” /></li>
 <li><img src=”7.jpg” alt=”” width=”100px” height=”100px” /></li>
 <li><img src=”8.jpg” alt=”” width=”100px” height=”100px” /></li>
 <li><img src=”9.jpg” alt=”” width=”100px” height=”100px” /></li>
 </ul>
</div>
<script type=”text/javascript”>
 //全局变量一定要少定义
 //容易出错 还占内存
 /*图标拖拽 
 1.如果想让图标移动 那就得把浮动布局改为浮动布局
 1.1
 操作系统和浏览器是多线程(伪多线程)
 是在非常短的时间内执行单个线程比如1um
 比如一秒内就可以完成多个单线程
 而JS是单线程
 当四个任务让浏览器执行的时候
 因为是单线程 谁执行快返回谁
 所以 写的代码有的时候和返回的而结果不一样
 2.当鼠标点住一张图片的时候 图片可以拖动(鼠标移动)
 2.1事件代理 点击事件 //有点行不通
 2.1 onmousedown onmousemove onmouseup
 循环给每个li元素加上
 2.2 记录点击的那个位置 两次鼠标位置相减 加上自身偏移量 都会改变left top值
 让图片跟着鼠标走
3.在拖动图片的时候碰撞检测
 3.1 计算与周围的图标的距离 距离最短的那个图片添加border
 3.2如果没有检测到 则松开鼠标的时候 图片回到原始位置
 3.3当松开鼠标的时候 图片位置平滑交换 
 3.4 
 */
 //获取元素的时候 不是数组 要转化为数组 或者 把所需要的内容添加到自定义数组中
 var liList=document.querySelectorAll(“.box ul li “);//伪数组
 var imgWrapper=document.querySelector(“.imgWrapper”);
 var nearElement=null;
 var arr=Array.prototype.slice.call(liList);
 var liPos=[];
 var sign=[];
 var num=1;
 var control=false;
function deleteBorder(arr){
for(var i=0,item;item=arr[i++];){
arr[i-1].style.border=””;
}
}
function pos(){
 /*设置比获取速度要快
 如果想让设置之在获取之后就要让他的执行速度变慢
 可以用定时器 定时器 要注意闭包作用域的问题
 函数立执行
 */
for( var j=0,len=arr.length;j<len;j++){
 liPos.push([arr[j].offsetLeft,arr[j].offsetTop]);
 //函数自执行
 (function(n){
 setTimeout(function(){
 arr[n].style.position=”absolute”; //把浮动改成定位
 arr[n].style.left=liPos[n][0]+”px”; //重新设置位置
 arr[n].style.top=liPos[n][1]+”px”;
 arr[n].style.margin=”0″;//margin设置为0 不然会有两个margin距离
 },0);
 })(j);
 }
 }
 pos();
 //mousedown mouseover mouseup
 //给每个li添加事件
 for(var i=0,item;item=arr[i++];){
 //给元素添加index属性
 arr[i-1].index=i-1;
 drag(arr[i-1]);
 }
 //拖拽
 function drag(obj){
 obj.onmousedown=function(e){
 e.preventDefault();
 var oldX=e.offsetX;
 var oldY=e.offsetY;
 ++num;
 obj.style.zIndex=num;
obj.onmousemove=function(e){
 var newX=e.offsetX;
 var newY=e.offsetY;
 obj.style.left=(newX-oldX+obj.offsetLeft)+”px”;
 obj.style.top=(newY-oldY+obj.offsetTop)+”px”;
 for(var i=0,len=arr.length;i<len;i++){
 if(!impact(obj,arr[i])&&obj!=arr[i]){
 if(!impact(obj,arr[i])){
 //记录下碰撞成功的元素
 sign.push(arr[i]);
 }
 else{
 //没有碰撞的话元素边框消失
 arr[i].style.border=””;
 }
 }
 }
 //在碰撞中的元素中找到最短的那个设置边框
 if(!(sign&&sign.length==0)){// 当sign数组里面没有元素的时候不执行 
 nearElement=nearDistance(obj,sign); 
 nearElement.style.border=”1px solid red”
 }
}
 }
 //鼠标抬起 平滑交换位置 动画
 obj.onmouseup=function(){
 obj.onmousemove=null;
if(!(sign&&sign.length==0)){
 move(obj,[liPos[obj.index][0],liPos[obj.index][1]],[liPos[nearElement.index][0],liPos[nearElement.index][1]]);
 move(nearElement,[liPos[nearElement.index][0],liPos[nearElement.index][1]],[liPos[obj.index][0],liPos[obj.index][1]]);
 deleteBorder(arr);
 //交换完之后 index 交换
 var index=nearElement.index;
 nearElement.index=obj.index;
 obj.index=index;
 //全局变量一定要注意 
 sign=[];
 }
 else{
 obj.style.left=liPos[obj.index][0]+”px”;
 obj.style.top=liPos[obj.index][1]+”px”;
 }
 }
}
 //碰撞检测
 function impact(obj1,obj2){
 var L1=obj1.offsetLeft;
 var T1=obj1.offsetTop;
 var R1=L1+obj1.offsetWidth;
 var B1=T1+obj1.offsetHeight;
 var L2=obj2.offsetLeft;
 var T2=obj2.offsetTop;
 var R2=L2+obj2.offsetWidth;
 var B2=T2+obj2.offsetHeight;
if(L1>R2||R1<L2||T1>B2||B1<T2){//满足其中任和一个 都不可能碰撞
return true;
 }
 else{
 return false;
 }
}
 //判断最短距离
 function nearDistance(obj,arr){
 //第一个数组里面保存的事li元素 第二个保存的是斜边长度
 //根据对应的斜边长度找到对应的元素
 var value=[[],[]];
 for(var i=0,len=arr.length;i<len;i++){
 //勾股定理
 var a=arr[i].offsetLeft-obj.offsetLeft;
 var b=arr[i].offsetTop-obj.offsetTop;
 //计算最短斜边
 value[0].push(arr[i]);
 value[1].push(Math.sqrt(a*a+b*b));
 } 
 //返回最小斜边对应的那个li元素 设置边框之前其他的边框清除 然后设置碰撞最短元素边框
 deleteBorder(arr);
 //这段代码可读性不太好
 return value[0][value[1].indexOf(Math.min.apply(Math,value[1]))];
 }
 //事件运动函数
 function move(obj,current,target){
 //X,Y轴都会变化
 //时间运动公式 s=t*S/T
 var T=500;
 var t=new Date();
 var Sx=target[0]-current[0];
 var Sy=target[1]-current[1];
 var timer=null;
 var stepX=0,stepY=0;
 var changeTime=0;
 //var currentX=0,currentY=0;
 timer=setInterval(function(){
 changeTime=new Date()-t;
 //currentX=obj.offsetLeft;
 //currentY=obj.offsetTop;
 if(changeTime/T>=1){
 clearInterval(timer);
 obj.style.left=target[0]+”px”;
 obj.style.top=target[1]+”px”;
 }
 else{
 stepX=parseInt(changeTime*Sx/T);
 stepY=parseInt(changeTime*Sy/T);
 obj.style.left=current[0]+stepX+”px”;
 obj.style.top=current[1]+stepY+”px”;
 }
},1000/60);
}
 </script>
 </body>
</html>
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/12286.html
