思路:
-
上傳一張自己的本地的圖片
-
將圖片分割成若干行若干列
+ 給每一個(gè)小格子,添加上自己的索引
+ 把索引存入一個(gè)數(shù)組中,方便最后判斷是否完成
-
分割的每一個(gè)小格子上都顯示完整圖片對(duì)應(yīng)的一部分
-
點(diǎn)擊開始游戲按鈕,打亂圖片的位置
+ 創(chuàng)建一個(gè)新數(shù)組,將原數(shù)組打亂之后存到新數(shù)組中
+ 讓每一個(gè)小格子根據(jù)打亂后的數(shù)組進(jìn)行定位
-
點(diǎn)擊兩個(gè)不同的小格,讓其交換位置。
+ 小格子位置交換完成后,需要將打亂的數(shù)組對(duì)應(yīng)的兩個(gè)值也交換位置。
-
判斷交換后的亂序數(shù)組和原來的數(shù)組是否相等,如果相等即表示游戲完成。
難點(diǎn):
-
如何上傳本地圖片讓其顯示的
-
如何將一張圖片切割成多個(gè)小格子
-
如果根據(jù)亂序的數(shù)組來計(jì)算當(dāng)前的行數(shù)和列數(shù)
解決辦法:
-
針對(duì)于如何上傳一張本體圖片,看之前的一篇關(guān)于瀏覽器如何在頁面上顯示準(zhǔn)備上傳的圖片的問題,下面是傳送門。
+ <a target = "_blank" href="http://www.itdecent.cn/p/9e4a1ee03089">關(guān)于瀏覽器如何在頁面上顯示準(zhǔn)備上傳的圖片的問題</a>
-
針對(duì)如何切割一張圖片的問題,事實(shí)上也并不能說是切割,且聽我細(xì)細(xì)道來。
+ 首先我們利用兩個(gè)for循環(huán),外層代表行數(shù),里面代表列數(shù),然后動(dòng)態(tài)創(chuàng)建div來表示每一個(gè)小方格。
+ 然后我們分隔好了小方格,我們也知道小方格的寬和高,并且知道每行每列各有多少個(gè)小方格。
+ 之后我們給每一個(gè)小方格都設(shè)置一個(gè)`background-image`屬性,讓每一個(gè)方格都有一個(gè)完整的圖。所以說這里并不是一張背景圖,而是有多少個(gè)小方格就有多少張圖片。
+ 再之后根據(jù)行數(shù)和列數(shù)的數(shù)量來設(shè)置`background-size`,比如只有一個(gè)格子,`background-size`的值就是 100% ,同理,兩個(gè)值就是200%
+ 最后根據(jù)當(dāng)前第幾行,第幾列,每一個(gè)小格子的寬度和高度來計(jì)算出偏移量,即left值和top值。再利用`background-position`來進(jìn)行定位即可實(shí)現(xiàn)。
-
針對(duì)根據(jù)亂序數(shù)組來計(jì)算當(dāng)前的行數(shù)和列數(shù)。這里其實(shí)也并不難,只是我個(gè)人卡在這里卡了一會(huì)兒。。。。
+ 首先我們的亂序數(shù)組是根據(jù)原來的數(shù)組打亂順序而來,所以里面的數(shù)值除了順序應(yīng)該就是一樣的。
+ 當(dāng)我們點(diǎn)擊圖片的時(shí)候能夠獲取到圖片所在的div的索引。
+ 因?yàn)樵瓟?shù)組是按照0,1,2,3,4.....這樣排列的,所以這個(gè)索引在亂序數(shù)組中對(duì)應(yīng)的值就是打亂后的圖片是從0開始數(shù)的第多少張圖片。
+ 知道了這張圖片此時(shí)是屬于第幾張,我們就能根據(jù)這個(gè)值來計(jì)算出這張圖片此時(shí)對(duì)應(yīng)的行數(shù)和列數(shù)。
- 當(dāng)前是第幾張圖片 / 一行多少列 然后取整 就是當(dāng)前屬于第幾行
- 當(dāng)前是第幾張圖片 % 一行多少列 然后取余 就是當(dāng)前屬于第幾列
這里我用一張動(dòng)圖來表示如果切割圖片的

如何把一張圖切割成多塊.gif
注意點(diǎn):
-
打亂索引 的時(shí)候要注意,由于打亂的數(shù)組可能跟原數(shù)組還是一樣,所以需要控制一下。
-
上傳的本地的圖片不要太大,不然讀取的速度那還真有點(diǎn)慢。。。
-
上傳的圖片需要是個(gè)正方形的,實(shí)在沒有正方向的話,高度大于寬度的圖片也行,無非是下半部分被干掉了。。
-
因?yàn)閭€(gè)人比較懶。很多地方?jīng)]有寫兼容,所以打開小游戲請(qǐng)使用chrome瀏覽器
我們來看看關(guān)鍵代碼
-
HTML部分
<!-- 獲取圖片 -->
<input type="file" id="file">
<!-- 字體圖標(biāo) -->
<div id="btn">
<i class="iconfont icon-xiangji2"></i>
</div>
<div id="gameArea">
<!-- 游戲開始按鈕 -->
<div id="gameStart">點(diǎn)擊開始</div>
<!-- 圖片存放的區(qū)域 -->
<div id="imgArea"></div>
</div>
-
CSS部分
css部分真沒啥好說的,有興趣的話大家下載源碼,一看就知道了
-
JS部分
- 切割圖片
// 切割圖片 imgSplit:function(){ // 清空?qǐng)D片存放區(qū)域 this.imgArea.innerHTML = ''; // 用來存方動(dòng)態(tài)創(chuàng)建的div元素 var _cell = ''; // 行數(shù) for (var i = 0, l =this.leverArr[0]; i<l ;i++) { // 列數(shù) for (var j = 0,l =this.leverArr[1]; j<l ;j++) { // 給每張圖片一個(gè)索引值 // 索引遞增規(guī)則為 從左到右 從上到下 this.imgOrigArr.push(i*this.leverArr[0] + j); // 創(chuàng)建div _cell = document.createElement('div'); // 給div添加id _cell.className = "imgCell"; // 給每張一個(gè)索引,方便后面點(diǎn)擊的時(shí)候進(jìn)行判斷 _cell.index = i*this.leverArr[0] + j; // 給div添加樣式 _cell.style.width = this.cellWidth+'px'; _cell.style.height = this.cellHeight+'px'; _cell.style.left = j*this.cellWidth+'px'; _cell.style.top = i*this.cellHeight + 'px'; _cell.style.backgroundImage= "url("+this.imgUrl+")"; // 這里因?yàn)?00%就讓背景圖的大小等于了一個(gè)小格子的大小 // 而我們只需要原始圖的一部分,并不是想縮小原圖 // 所以根據(jù)小格子的個(gè)數(shù)來放大圖片 _cell.style.backgroundSize = this.leverArr[1]+'00%'; // 移動(dòng)背景圖,行成最后切成的一塊塊的效果 _cell.style.backgroundPosition = (-j)*this.cellWidth + 'px ' + (-i)*this.cellHeight+'px'; // 讓背景圖從邊框開始平鋪 _cell.style.backgroundOrigin = "border-box"; this.imgArea.appendChild(_cell); } } // 獲取小格子的dom元素 this.imgCells = document.querySelectorAll('.imgCell'); //將選擇圖片的按鈕移動(dòng)到可視區(qū)域外 this.btnObj.style.left= -this.btnObj.offsetWidth+'px'; // 將圖片移入可視區(qū)域 // this.gameAreaObj.style.background = 'url('+this.imgUrl +')'; this.gameAreaObj.style.left = '50%'; this.gameAreaObj.style.transform= 'translate(-50%,-50%)'; // 使按鈕綁定事件,點(diǎn)擊按鈕開始整個(gè)游戲 this.gameStartBtnObj.onclick = this.clickHandle(); } - 打亂圖片索引
// 打亂圖片索引 randomArr:function(){ // 清空亂序數(shù)組 this.imgRandomArr = []; // 判斷原來的數(shù)組是否和亂序數(shù)組一樣 var _flag = true; // 遍歷原始索引 for(var i=0,l=this.imgOrigArr.length;i<l;i++){ // 獲取從0到數(shù)組長度之間的一個(gè)索引值 var order = Math.floor(Math.random()*this.imgOrigArr.length); // 如果亂序數(shù)組中沒有值就直接添加 // 否則就在這個(gè)亂序數(shù)組中找對(duì)應(yīng)的隨機(jī)數(shù)的索引,找不到就添加,找到就繼續(xù)隨機(jī) if(this.imgRandomArr.length>0){ while(this.imgRandomArr.indexOf(order) >-1){ order = Math.floor(Math.random()*this.imgOrigArr.length); } } this.imgRandomArr.push(order); } // 判斷亂序數(shù)組和原始數(shù)組是否一樣 if(this.imgRandomArr.length === this.imgOrigArr.length){ // 遍歷數(shù)組 for(var i=0,l=this.imgOrigArr.length;i<l;i++){ if(this.imgRandomArr[i] != this.imgOrigArr[i]){ _flag = false; break; }else{ _flag = true; } } }else{ _flag = true; } // 返回值為true的話 就代表原始數(shù)組和亂序數(shù)組一致,重新打亂數(shù)組 if(_flag){ this.randomArr(); } } - 交換兩次點(diǎn)擊的圖片位置
// 交換兩次點(diǎn)擊的圖片位置 cellExchange:function(from,to){ // 因?yàn)閳D片此時(shí)的排序是根據(jù) 以圖片的索引值為索引 // 在亂序的數(shù)組中根據(jù)相對(duì)應(yīng)的索引取出的值作為當(dāng)前圖片的排序位置的 // 因此根據(jù)from to這兩個(gè)值作為索引,就能在亂序數(shù)組中得到當(dāng)前圖片是第幾張 // 求出from的圖片 是第幾行第幾列 // 當(dāng)前是第幾張圖片 / 一行多少列 然后取整 就是當(dāng)前屬于第幾行 var _fromRow = Math.floor(this.imgRandomArr[from] / this.leverArr[1]); // 當(dāng)前是第幾張圖片 % 一行多少列 然后取余 就是當(dāng)前屬于第幾列 var _fromCol = this.imgRandomArr[from] % this.leverArr[1]; // 求出to的圖片 是第幾張第幾列 var _toRow = Math.floor(this.imgRandomArr[to] / this.leverArr[1]); var _toCol = this.imgRandomArr[to] % this.leverArr[1]; // 移動(dòng)兩張圖片 this.imgCells[from].style.left = _toCol*this.cellWidth + 'px'; this.imgCells[from].style.top = _toRow*this.cellHeight + 'px'; this.imgCells[to].style.left = _fromCol*this.cellWidth + 'px'; this.imgCells[to].style.top = _fromRow*this.cellHeight + 'px'; // 將亂序數(shù)組中的兩個(gè)值交換位置 // 定義一個(gè)臨時(shí)變量來實(shí)現(xiàn)交換順序 var _temp = this.imgRandomArr[from]; this.imgRandomArr[from] = this.imgRandomArr[to]; this.imgRandomArr[to] = _temp; //如果亂序數(shù)組和原數(shù)組一致,則表示拼圖已完成 if(this.imgOrigArr.toString() === this.imgRandomArr.toString()){ // 調(diào)用成功方法 this.success(); } }
源碼保存在了<a target = "_blank" >github</a>上,有愛點(diǎn)擊github自取。
在線地址可以直接測(cè)試使用,<a target = "_blank" >拼圖小游戲</a>←點(diǎn)擊跳轉(zhuǎn)即可
總結(jié):
- 最近不知道怎么了,老是不在狀態(tài),腦袋反應(yīng)比較慢,一個(gè)簡(jiǎn)單問題總是要想好久。感覺整個(gè)人都魔怔了。。。。
- 本來我是想自動(dòng)獲取圖片寬高來切成行列的,不過行數(shù)列數(shù)不相等的話,好像有點(diǎn)麻煩。而且不是正方形也不好看啊。想了想還是不弄了。。想興趣的朋友自己弄弄吧。。
- 順便一提,上面的動(dòng)圖所用到的圖片,畫師是P站的 METO@三日目東ミ24a