# JS_練習_可排序表單
能夠將電腦亂排順序的名單,自由選取排列,排列正確會變綠色,順序錯誤會是紅色。
- 純HTML畫面

- 成品畫面

### 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);
});
}
```
- 函式外呼叫函式,畫面呈現。

- 加入partII/ part III

- 加入part IV

#### 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`