# JS_練習_可排序表單 能夠將電腦亂排順序的名單,自由選取排列,排列正確會變綠色,順序錯誤會是紅色。 - 純HTML畫面 ![](https://i.imgur.com/PtjhA6y.png) - 成品畫面 ![](https://i.imgur.com/R7NgtJh.png) ### HTML 再HTML建立空白的無序列表,等JS再將內容加至設定好的`ul`,最後再加上一個`button`以執行JS已確認排序是否正確。 ```.html <h1>Top 10 Videos on Youtube 2020</h1> <p>Drag and Drop items into their corresponding spots</p> <ul class="draggable-list" id="draggable-list"> </ul> <button class="check-btn" id="check-btn"> Check Order <i class="fas fa-paper-plane"></i> </button> ``` ### CSS #### body::after 在根元素`body`後面,透過偽元素選擇器,使整個body加上一層半透明的黑影,使畫面看起來質感加分。 ```.css body::after { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.6); } ``` #### 偽類 常見的偽類樣式: - `:active`:滑鼠按下會產生的狀態。 - `:focus`:鍵盤聚焦會產生的狀態。 - `:hover`:滑鼠滑過會產生的狀態。 - `:link`:還沒訪過會產生的狀態。 - `:visited`:被訪過會產生的狀態。 ## JS ### 實現步驟 - 創造一個陣列放入容器,陣列是有索引值與內容。 - 利用sort方法將隨機產生的索引值按照大小排列, - ### Drag and Drog API - 創造要丟進DOM的陣列 ```.js - const hottestVideo = [ '羅一鈞副組長', '蔡阿嘎與孕婦二伯', '粿粿-花蓮落下事件', '這群人-請假經典語錄', '黃氏兄弟-我想跟家人說', '中指通的歐美女優精選', '孫生去監獄看媽媽', '狠愛演-謝謝大家', '反正我很閒-卑鄙源之助的一天', '東森51-臨終前最後26秒奮力道別' ] ``` ### creatList() - 利用`...`將陣列展開變成個別的值。 - 利用`forEach()`將每個陣列的值,都放到 li 裡,並設定li裡的屬性及加上索引值。 - 填入HTML的內容在我們所定義好屬性的陣列裡。 - part II: 利用`map()`方法創造新陣列。回傳 - 該影片的value - 創造一個sort,並用`Math.random`方法隨機產生0~1的數字 - part III: 利用sort方法將random出來的數字按照大小排列。 - part IV: 再利用map方法將我們part II產生的value [sort()小科普](https://realdennis.medium.com/javascript-%E5%BE%9Earray%E7%9A%84sort%E6%96%B9%E6%B3%95-%E8%81%8A%E5%88%B0%E5%90%84%E5%AE%B6%E7%80%8F%E8%A6%BD%E5%99%A8%E7%9A%84%E5%AF%A6%E4%BD%9C%E7%AE%97%E6%B3%95-c23a335b1b80) ```.js creatList() //creat List items into DOM function creatList(){ [...hottestVideo] //part II .map(function(a){ return{ value:a , sort: Math.random() } })//part III .sort(function(a,b){ return (a.sort - b.sort) })//part IV .map(function(a){ return a.value }) .forEach(function(video,index) { const listItem = document.createElement('li'); //index =0~9 listItem.setAttribute('data-index', index); listItem.innerHTML = ` <span class ='number'>${ index + 1 }</span> <div class ="draggable" draggable ="true"> <p class ="video-name">${video}</p> <i class = "fas fa-grip-lines></i> </div> `; listItems.push(listItem); draggableList.appendChild(listItem); }); } ``` - 函式外呼叫函式,畫面呈現。 ![](https://i.imgur.com/GXgLXsv.png) - 加入partII/ part III ![](https://i.imgur.com/0KdF1YZ.png) - 加入part IV ![](https://i.imgur.com/s6PQD20.png) #### addEventListener() - [drag event 小科普](https://developer.mozilla.org/zh-CN/docs/Web/API/HTML_Drag_and_Drop_API) - 設定 ==drag==事件,其中分為兩項觸發 - 被選擇的物件。 - dragstart 方法就是在物件開始拖曳時觸發。 - 在觸發事件時利用`closest()`方法取得當前元素最近得祖先元素,並透過`getAttribute得到該元素的index` [closest()小科普](https://developer.mozilla.org/zh-CN/docs/Web/API/Element/closest) - 可以當作目標的物件。 - dragleave 是當被選擇物件被拖曳到可以當作目標物件的上方時,在離開目標物件上方時,瞬間觸發。 - dragover 當被選擇物件被拖曳到可以當目標物件上方時觸發。是目標物件觸發!不是被選擇物件。 - drop 當被選擇物件被拖曳到目標物件時觸發。是目標物件觸發!不是被選擇物件。 - 建立函式`swapItem()`,利用最上面先建立一個空陣列listitems。再設立參數並將值選出且利用`appendChild`賦值,將內容進行交換。 ```.js addEventListeners() }); } function dragStart() { // console.log('event: ' , 'drapstart') dragStartIndex = this.closest('li').getAttribute('data-index'); // console.log(dragStartIndex); } function dragOver() { console.log('event: ' , 'drapover') } function dragDrop() { // console.log('event: ' , 'drapDrop') const dragEndIndex = +this.getAttribute('data-index') swapItems(dragStartIndex, dragEndIndex); this.classList.remove('over'); } function swapItems(fromIndex, toIndex){ // console.log(124); const itemOne = listItems[fromIndex].querySelector('.draggable') const itemTwo = listItems[toIndex].querySelector('.draggable'); // console.log(itemOne, itemTwo); listItems[fromIndex].appendChild(itemTwo); listItems[toIndex].appendChild(itemOne); } function dragLeave() { console.log('event: ' , 'dragleave') } function dragEnter() { console.log('event: ' , 'dragenter') } function addEventListeners(){ const draggables = document.querySelectorAll('.draggable') const dragListItems = document.querySelectorAll('.draggable-list li') draggables.forEach(function(draggable){ draggable.addEventListener('dragstart', dragStart); }); dragListItems.forEach(function (item) { item.addEventListener('dragover', dragOver); item.addEventListener('drop', dragDrop); item.addEventListener('dragenter', dragEnter); item.addEventListener('dragleave', dragLeave); }); } ``` #### click event 將HTML所設定的button,綁定一個`click事件`,呼叫`checkOrder`函式。 #### checkOrder() 由於上面有設定random公式,當畫面reload時,是隨機排列的。我們將列表重新排序時,最後點下btn,確認是否排列正確。 設定變數`videoName`取得listItem裡的文字, 將`videoName`跟原先設定好的`listItem[]`裡相同位置的文字進行比對。 若不相同 =>加上屬性 `wrong` 若相同 =>移除屬性 `wrong`增加屬性`right` ```.js $('#check-btn').click(checkOrder); function checkOrder(){ listItems.forEach(function(listItem, index){ const videoName = listItem.querySelector('.draggable').innerText.trim(); // console.log(videoName) if(videoName !== hottestVideo[index]){ listItem.classList.add('wrong'); }else{ listItem.classList.remove('wrong'); listItem.classList.add('right'); } }) } ``` ###### tags: `javascript`