# JavaScript - 拼圖 * 完成範例:[CodePen](https://codepen.io/liu_0821/pen/JjxagBm)、[GitHub](https://github.com/liu-huangling/JSPractice)、[Medium](https://medium.com/@LindaLiu0821/javascript%E5%9C%B0%E4%B8%8B%E5%9F%8E12-%E6%8B%BC%E5%9C%96-2b39d3959a5a) ![屏幕截图 2023-12-15 165116 (小)](https://hackmd.io/_uploads/rJQp7qYLp.png) > 12F - 拼圖 ### 使用語法 * HTML、CSS(SCSS)、原生JS(雖然有導入jquery的框架,但是就只當作備案) ### 攻略要點 1. 【特定技術】使用原生 JS。 2. 【特定技術】在設計稿上,總計有三個介面 3. 【特定技術】注重「遊戲體驗」 4. 例如說拼圖移動不可移動到瀏覽器外,拉不回來,必須都在遊戲介面內移動 5. 【書寫能力】請寫篇部落格,描述你在做此關時,「所遇到的瓶頸,以及你是如何克服的」 ### 拆解步驟 * **HTML** * 這次主要分成三大區塊來完成整個遊戲體驗 * 第一個介面就是準備開始遊戲,中間圖片會發出特效跟發出淡淡白色外陰影光芒 * 第二個介面是開始拼圖,拼圖位置隨機,但放到正確的位置上才算成功 * 第三個介面是顯示右側該拼圖的介面,全部頁面都在同頁面呈現 * **CSS(SCSS)** * 這次css的部分其實也不難,但我覺得在第一個畫面的動畫很有趣,所以有特地把它做出來,一樣是用<font color=cake>**`偽元素`**</font>跟<font color=cake>**`animation`**</font>,再來利用<font color=purple>**`animation-delay 動畫時間差`**</font>以及設定透明度做出往外散出去的感覺,就順利的做出來啦~~ * 這次也有重新複習到 <font color=purple>**`outline`**</font>、 <font color=purple>**`border`** </font>的用法,兩者使用方式很像,但有兩個不太一樣的地方為: | 名稱 | <font color=purple>**outline**</font> | <font color=purple>**border** </font> | | -------- | -------- | -------- | | 空間 | <font color=red>**不**</font>佔實體空間 | 佔實體空間 | | 邊框 | 只能為矩型,且<font color=red>**無法**</font>單邊設定 | 可設定圓角,可單邊設定 | * **JavaScript** * **主要流程**: * 創建拼圖 * 設定隨機位置 * 偵測移動drag開始/ 移動 / 放置 / 結束 * 遊戲結束導入畫面 * **創建拼圖** 建立迴圈創建放置拼圖的`div`跟拼圖本身後,`appendChild`至網頁上。 ![S__10682370](https://hackmd.io/_uploads/r1PPDV6Ua.jpg) > 比較需要注意的地方拼圖跟放置拼圖區塊的添加位置不相同! * 除此之外,圖片要多加上 **`draggable = true`** 為我們後面的事件鋪路。 * **更新隨機位置** 更新位置或是在剛開始需要隨機打散拼圖位置,但又不讓他超出本身螢幕大小。 * 需要將圖片 **`position`** 設定成<font color=cake>**absolute**</font>,透過設定left跟top來改變他的位置。 ``` PuzzleX = Math.abs(document.documentElement.clientWidth - Math.random() * document.documentElement.clientWidth - Puzzle.width); PuzzleY = Math.abs(document.documentElement.clientHeight - Math.random() * document.documentElement.clientHeight - Puzzle.height); ``` > 偵測瀏覽器窗口大小 - 隨機小數 * 偵測瀏覽器窗口大小 - 拼圖長寬 * 用`Math.abs()`取正數,將數值帶入left跟top,即完成。 * **偵測移動drag開始/ 移動 / 放置 / 結束** 使用<font color=cake>**forEach**</font>讓他遍歷所有元素,並設定監聽器。 ![屏幕截图 2023-12-18 114255](https://hackmd.io/_uploads/SJoAJrTI6.png) > 圖片來源:https://lotabout.me/2018/HTML-5-Drag-and-Drop/ * <font color=purple>**dragstart**</font> * 設定於<font color=cake>**被拖動的元素**</font> - 拼圖。 * **當元素一被拖動就會觸發**,並要設定 <font color=cake>**`draggable = true`**</font> 。 ``` // container 為我們設定的變數,在此帶入我們拖曳的元素。 container = e.target; ``` > **dragstart** 函式內容 * <font color=purple>**dragleave**</font> * 設定於於<font color=cake>**被放置的元素**</font> - 拼圖框。 * **當被拖動的元素離開會被觸發** 。 ``` // 取消hover效果 e.toElement.classList.remove('hover'); ``` > **dragleave** 函式內容 * <font color=purple>**dragover**</font> * 設定於於<font color=cake>**被放置的元素**</font> - 拼圖框。 * **當被拖動的元素移動或停止被放置的元素上會被觸發(最常被觸發)** 。 ``` e.preventDefault(); if(e.target.className == "puzzleBox"){ // 新增hover效果 e.toElement.classList.add('hover'); } ``` > **dragover** 函式內容 * <font color=purple>**drop**</font> * 設定於於<font color=cake>**被放置的元素**</font> - 拼圖框。 * **當被拖動的元素移動至被放置的元素上,並將滑鼠鼠標放開會被觸發**。 ``` // 拼圖對比數值 let divNum = e.target.dataset.num; // 拼圖框對比數值 let puzzleNum = container.dataset.checkNum; // 比較是否將拼圖放置在對應位置上 if(divNum == puzzleNum){ container.style.left = 0; container.style.top = 0; if(divNum != 1|| divNum != 3 || divNum != 4){ container.classList.add('puzzle-'+divNum); } // 拼圖放入至對應拼圖框內 e.target.appendChild(container); // 判斷全部位置函數 checkAllDom(); } // 取消hover效果 e.toElement.classList.remove('hover'); ``` > **drop** 函式內容 * **遊戲結束導入畫面** 判斷所有拼圖是否都有放置到正確的位置,並顯示結束畫面。 * 透過判斷所有的拼圖框是否都有拼圖 **`<img>`** 元素。 * `hasChildNodes()`判斷元素(element) 物件(object) 是否有子代(child) 。 ### 結尾 * 這次挑戰雖然整體`JavaScript`不到150行,但中間過程有點微痛苦QQ,一直在思考怎麼樣寫比較好,圖片位置怎麼放,應該如何移動,也一直陷在圈圈裡面,但莫名其妙的有一天下午就突然寫出來ㄌ??-`д´-?? ,總結真是可喜可賀可口可樂~~ ### 參考資料 * [HTML 5 Drag and Drop講解 ](https://lotabout.me/2018/HTML-5-Drag-and-Drop/):這篇講得很詳細,關於拖曳的事件活動說明。 * [同學的範例](https://medium.com/%E6%82%A0%E9%81%8A%E9%AD%9A%E4%B8%96%E7%9A%84%E8%87%AA%E5%8B%95%E5%8C%96%E7%AD%86%E8%A8%98/js%E5%9C%B0%E4%B8%8B%E5%9F%8E%E3%83%BC%E6%8B%BC%E5%9C%96-12ceef3d9092):我們寫的方式不太一樣,但是我覺得他講得很完整。 * [關於元素尺寸與位置](https://www.shubo.io/element-size-scrolling/) --- ##### ヽ(∀゚ )人(゚∀)人( ゚∀)人(∀゚ )人(゚∀)人( ゚∀)ノヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人( ゚∀)人 ##### 以上 如果哪裡有錯誤或有問題,歡迎提出來一起討論~~~~