<!doctype html><html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content=""> <meta name=" ...
<!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>