js原生图片拼图Demo
自從找著了工作后已經有將近三個月沒有寫博客啦。最近在加強js的邏輯練習,所以收集了一些js小練習,手把手把它敲出來了。我把它記錄下來,我的學習分享,嘿嘿。。。
貼下界面:
圖一 ?界面
這個拼圖游戲主要分為幾個步驟:
(1)小圖片列表切換,點擊顯示相應的大圖(大圖是由20張小圖片拼連起來的)
(2)點擊開始游戲后,20張小圖片隨機排序
(3)此時鼠標移到大圖上顯示移動狀態(tài),可以拖動,開始記錄時間
(4)碎片拼成原圖后顯示拼圖成功以及所花的時間
下面我來分解一下流程:
(1)先展示html及css的代碼:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>拼圖游戲</title> 6 <style> 7 body,ul,li{margin:0;padding:0;text-align: center;} 8 body{font:30px/1.5 Tahoma;} 9 #box{position:relative;width:1024px;height:768px;margin:10px auto;background:#808080;} 10 #box li{float:left;width:256px;height:154px;overflow:hidden;} 11 #box li img{width:256px;height:154px;} 12 #box li.hig{width:256px;height:154px;overflow:hidden;border:2px dashed yellow;} 13 #box li.hig img{width:256px;height:154px;opacity:0.5;filter:alpah(opacity=50);} 14 #mask{position:absolute;top:0;left:0;width:1024px;height:768px;background:red;opacity:0;filter:alpha(opacity=0);} 15 input{cursor:pointer;} 16 #photo{text-align:center;margin:10px 0;} 17 #photo img{width:100px;height:auto;border-radius:5px;margin:0 5px;opacity:0.5;filter:alpha(opacity=50);cursor:pointer;} 18 #photo img.hover{opacity:1;filter:alpha(opacity=100);} 19 #photo img.selected{border:2px solid yellow;width:96px;height:auto;opacity:1;filter:alpha(opacity=100);} 20 </style> 21 </head> 22 <body> 23 <div id="photo"><img src="img/flower/img_01.jpg" class="selected" /><img src="img/flower/img_02.jpg" /><img src="img/flower/img_03.jpg" /></div> 24 <input type="button" value="開始游戲" id="play-btn"/> 25 <ul id="box"></ul> 26 </body> 27 </html> View Code首先實現(xiàn)如下的效果:
說明:鼠標懸浮到小圖片上,圖片透明度變?yōu)?0%,點擊圖片,產生黃色邊框,下面的大圖也跟著變化,點擊開始按鈕,內容會變成重新開始
js代碼:
1 var oPhoto=document.getElementById("photo"); 2 var aThumbImg=oPhoto.getElementsByTagName('img'); 3 var oStartBtn=document.getElementById("play-btn"); 4 var oBox=document.getElementById("box"); 5 var isRandom=false; 6 var dirPath=0;var odata=[]; 7 for(var i=0;i<20;i++){ 8 var temp=i+1; 9 odata.push(temp); 10 } 11 for(var i=0;i<aThumbImg.length;i++){ 12 aThumbImg[i].index=i; 13 } 14 oPhoto.οnmοuseοver=function(ev){ 15 var ev = ev || window.event; 16 var target = ev.target || ev.srcElement; 17 if(target.nodeName.toLowerCase()=='img'){ 18 target.className+=' hover'; 19 } 20 } 21 oPhoto.οnmοuseοut=function(ev){ 22 var ev = ev || window.event; 23 var target = ev.target || ev.srcElement; 24 if(target.nodeName.toLowerCase()=='img'){ 25 target.className=target.className.replace(/\shover/,''); 26 } 27 } 28 oPhoto.οnclick=function(ev){ 29 var ev = ev || window.event; 30 var target = ev.target || ev.srcElement; 31 if(target.nodeName.toLowerCase()=='img'){ 32 for(var i=0;i<aThumbImg.length;i++){ 33 aThumbImg[i].className=''; 34 } 35 target.className='selected'; 36 dirPath=target.index; 37 oStartBtn.value='開始游戲'; 38 oBox.innerHTML="" 39 odata.sort(function(a,b){ 40 return a-b; 41 }); 42 43 } 44 } 45 oStartBtn.οnclick=function(){ 46 this.value="重新開始"; 47 oBox.innerHTML=""; 48 }
上面都是比較簡單的,這個游戲的核心還是在于邊界判斷,移動上。
(2)現(xiàn)在來實現(xiàn)拖動這一部分,先講解onmousedown和onmousemove事件
2.1 首先,還未開始游戲時,我設置了一層遮罩,就是不讓其拖動,所以我們來建個遮罩層,也是放在id='box'里面,跟li同級。
oPhoto.οnclick=function(ev){creatMask(); }function creatMask(){var mask=document.createElement('div');mask.id='mask';mask.style.zIndex=zIndex;oBox.appendChild(mask); } creatMask();當進入頁面是生成遮罩層,點擊小圖片時,遮罩層還存在,只有點擊開始游戲時,才會移除遮罩層。這時候,圖片切塊才能開始拖動。
2.2 點擊開始游戲,給圖片切塊注冊onmousedown和onmousemove事件
1 function drag(obj){ 2 obj.style.cursor='move';obj.οnmοusedοwn=function(event){ 3 var event=event||window.event; 4 event.preventDefault(); 5 var start_x=event.clientX-this.offsetLeft; 6 var start_y=event.clientY-this.offsetTop; 7 obj.style.zIndex = zIndex++;
document.οnmοusemοve=function(event){ 8 var event=event||window.event; 9 event.preventDefault(); 10 var iL=event.clientX-start_x; 11 var iT=event.clientY-start_y; 12 var maxL=obj.parentNode.clientWidth-obj.offsetWidth; 13 var maxT=obj.parentNode.clientHeight-obj.offsetHeight; 14 //邊界判斷 15 if(iL<0){iL=0;} 16 if(iT<0){iT=0;} 17 if(iL>maxL){iL=maxL;} 18 if(iT>maxT){iT=maxT;} 19 obj.style.left=iL+'px'; 20 obj.style.top=iT+'px'; 22 } 23 } 24 }
上面的代碼主要實現(xiàn)了圖片拖動,且拖動范圍不能超過box的范圍。
好了,現(xiàn)在要實現(xiàn)拖動的小塊與周邊的切片的碰撞檢測,與之最近的切塊顯示黃色邊框
效果:
?
這其中的原理是:? 查找拖動塊附近的最近的li,然后給li容器添加黃色邊線。
js代碼:
function findNear(obj){var minLi=null;var minNum=Number.MAX_VALUE;var filterLi=[];var aDistance=[];for(var i=0;i<aLi.length;i++){if(aLi[i]!=obj&&isButt(obj,aLi[i])){ aDistance.push(getDistance(obj,aLi[i]));filterLi.push(aLi[i]);}}var minNum=Number.MAX_VALUE;//遍歷查詢最小值for(var i=0;i<aDistance.length;i++){if(aDistance[i]<minNum){minNum=aDistance[i];minLi=filterLi[i];}}return minLi;} function isButt(obj1,obj2){var l1=obj1.offsetLeft;var lw1=obj1.offsetWidth+l1;var t1=obj1.offsetTop;var th1=obj1.offsetTop+t1;var l2=obj2.offsetLeft;var lw2=obj2.offsetWidth+l2;var t2=obj2.offsetTop;var th2=obj2.offsetTop+t2;//上下左右判斷return !(th2<t1||th1<t2||lw2<l1||lw1<l2);}function getDistance(obj1,obj2){var dir_x=(obj1.offsetLeft+obj1.offsetWidth/2)-(obj2.offsetLeft+obj2.offsetWidth/2);var dir_y=(obj1.offsetTop+obj1.offsetHeight/2)-(obj2.offsetTop+obj2.offsetHeight/2);var dir=Math.sqrt(dir_x*dir_x+dir_y*dir_y);return dir;}然后在onmousedown里面調用
var oNear=null; for (i = 0; i < aLi.length; i++) aLi[i].className = "";oNear=findNear(obj);//返回一個最靠近obj的塊//對最近的塊顯示黃色邊框if(oNear){oNear.className='hig';}邊界判斷、isButt()函數(shù)、 findNear()函數(shù)和的分析圖:
(3)實現(xiàn)了移動拖動這一部分,那么鼠標釋放時,又怎么實現(xiàn)拖動塊與最近切片的位置交換呢。
首先,得先清楚一點,取個例子:
<ul id="box"><li>1</li><li>2</li><li>3</li> </ul>不管你怎么拖動里標簽,改變的只是他的left和top,li標簽在文檔的先后順序是不會改變的。那我們來看看li標簽拖動過程的變化,如下圖:
?
js代碼:
document.οnmοuseup=function(event){document.onmousemove = null;//移除事件document.onmouseup = null;var event=event||window.event;event.preventDefault();//鼠標釋放后碎片與目標碎片對換if(oNear){var obj_index=obj.index;obj.index=oNear.index;oNear.index=obj_index;//obj移動到oNear的位置 startMove(obj,oPos[obj.index]);//oNear移動到obj的位置startMove(oNear,oPos[oNear.index],function(){//判斷碎片是否還原成功// console.log(finish());if(finish()){alert('恭喜你,拼圖游戲完美成功!!!');creatMask();} });oNear.className="";//移除黃色邊框}else{//回到原位 startMove(obj,oPos[obj.index]);}} function startMove(obj,pos,onEnd){obj.timer=setInterval(function(){doMove(obj,pos,onEnd); },30); }
function doMove(obj,pos,onEnd){var curOffsetLeft=obj.offsetLeft;var curOffsetTop=obj.offsetTop;//下面設置圖片碎片每次向目標點移動的位移var speedL=(pos.left-curOffsetLeft)/5;var speedT=(pos.top-curOffsetTop)/5; speedL=speedL>0 ? Math.ceil(speedL) : Math.floor(speedL);speedT=speedT>0 ? Math.ceil(speedT) : Math.floor(speedT);obj.style.left=(curOffsetLeft+speedL)+'px'; obj.style.top=(curOffsetTop+speedT)+'px';//當obj的left等于對換oNear所保存的left,說明已經和它完全吻合了。此時移除計時器。if(curOffsetLeft==pos.left && curOffsetTop==pos.top){clearInterval(obj.timer);//如果傳入回調函數(shù),則執(zhí)行回調函數(shù)onEnd && onEnd(); // return; } } function finish(){var success=true;var tempArr=[];tempArr.length=0;for(var i=0;i<aLi.length;i++){for(var j=0;j<aLi.length;j++){if(i==aLi[j]['index']){//li標簽內圖片的序號添加進數(shù)組var img=aLi[j].getElementsByTagName('img')[0];//返回匹配到的子集元素var srcIndex=img.src.match(/\/(\d+).jpg/)[1]; // console.log(srcIndex); tempArr.push(srcIndex);}} }for(var i=1;i<=tempArr.length;i++){if(i!=tempArr[i-1]){success=false;break;}}return success;
}
好啦,整個過程就是這樣子。拿來練手還是不錯的。
demo中的圖片碎片是我原先切好的,其實我本來是想將原圖用程序裁切的,奈何技術不夠,所以只能用ps處理了一下,這是我覺得比較遺憾的事啦,有興趣的你可以實現(xiàn)一下唄。。。
這里是demo的源代碼地址:https://coding.net/u/U_can/p/puzzleGame/git。
?
轉載于:https://www.cnblogs.com/U-can/p/4975335.html
總結
以上是生活随笔為你收集整理的js原生图片拼图Demo的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FreeMarker缓存处理
- 下一篇: 浅谈Struts2的命名空间及以传统形式