# 每日任務重點筆記
>[TOC]
<style>
.blue {
color: blue;
}
</style>
### 變數宣告(let、const)
**知識點:使用 let、const 宣告變數**
* const: 一般使用在變數不會被重新指定值
* let:一般使用在變數可能會被重新指定值
---
### 型別判斷(數字、字串、NAN...)
**知識點:型別判斷**
* 數字 + 字串 = 字串
* 數字字串 * 數字字串 = 數字
* 數字 - 數字字串 = 數字
* 數字 - 中文字串 = NAN
* 數字 * 中文字串 = NAN
```
let a = 1 +"2"+ 3 ;
let b = "1" * "1";
let c = 2 - "1";
let d = "我好棒" - 1;
let e = 1 * "我好棒";
// 印出 "123" 1 1 NaN NaN
```
---
### 字串處理實用方法及如何轉型(parseInt()、toString())
**知識點:字串處理**
* 過濾空白方法:字串.trim()
* 字串轉型為數字:parseInt(字串)
* 數字轉型為字串:數字.toString()
```
let myEmail = " 123456@gmail.com";
let myPassword = " 987654321";
myEmail = myEmail.trim();
myPassword = myPassword.trim();
let a = "1";
let b = "2";
a = parseInt(a);
b = parseInt(b);
let countryCode = 886;
let myNumber = 123456789;
countryCode = countryCode.toString();
myNumber = myNumber.toString();
```
---
### 邏輯運算子
**知識點:**
* 比較與邏輯運算子
* 流程判斷 - if、else if、else
* 使用語法:|| &&
___
### 陣列宣告、取值、新增
**知識點:**
* 陣列的基礎寫法:
外層使用[ ]包覆,內層元素間用逗號區隔,在讀取陣列時會由零開始
```
let array = [0,1,2];
console.log(array[0])//陣列的讀取方法,從零開始
console.log(array.length)//讀取陣列長度
```
* 陣列的新增方法:
```
let array = ['item1'];
console.log(array);//["item1"]
//陣列預設寫入資料
array[1] = 'item2';
console.log(array);//["item1","item2"]
//push 寫入資料
array.push('item3');
console.log(array);//["item1","item2","item3"]
//unshift 寫入資料
array.unshift('item0');//["item0", "item1", "item2", "item3"]
console.log(array);
```
---
### 物件宣告、取值、新增
**知識點:**
**以下兩個方法可以讀取物件:**
1. 使用`.`點記法
```javascript=
let obj = {
myName:'王小花',
};
//讀取物件屬性
console.log(obj.myName)//王小花
//新增物件屬性
obj.key = 'value';
console.log(obj)//{myName: "王小花", key: "value"}
```
2. 使用`[]`括弧記法
通常情況下會使用`.`取值,但某些情況無法用`.`取值,例如屬性為數字開頭時,或要讀取變數的情況下皆會使用`[]`。
```javascript=
let obj = {
myName:'王小花',
};
//讀取物件屬性
console.log(obj['myName']);//王小花
//新增物件屬性
obj['key'] = 'value';
console.log(obj);//{myName: "王小花", key: "value"}
//讀取變數的情況
let a = 'myName';
console.log(obj[a])//王小花
```
---
### 函式、return
**知識點:**
**以 return 寫法:**
``` javascript
function calcTotalScore(chineseScore,mathScore){
return chineseScore + mathScore; //回傳,會把值回傳到呼叫 calcTotalScore 的地方
}
// return 回傳後的值,可以被賦予在變數上
//我宣告一個變數,名為 markTotalScore,並賦予右邊函式的值。
let markTotalScore = calcTotalScore(40,60);//會先將參數丟進 calcTotalScore 運算後,接收 return 回傳的值
console.log(markTotalScore)//100
```
---
### DOM 選取網頁元素
**知識點:**
1. **querySelector、textContent、 innerHTML**
2. **textContent、innerHTML 差異**
* 選取 HTML 元素
* 選取 class、id
* 透過後代選擇器方式,選取節點
```htmlembedded=
<ul class="list">
<li></li>
</ul>
```
```javascript=
const listContent = document.querySelector('.list li');
```
當我們透過 querySelector 選擇到節點後,就能使用 textContent 來動態修改裡面的 Text 文字內容
```htmlembedded=
<h1></h1>
```
```javascript=
//使用 querySelector 選取到 h1 Element
const el = document.querySelector('h1');
// 針對該 h1 元素 Element 去賦予文字內容
el.textContent = "Hello World";
```
當我們透過 querySelector 選擇到節點後,就能使用 innerHTML 來增加 HTML 網頁結構,innerHTML 會將選取到的結構內原有內容刪除,並重新寫入新增的內容,以下將示範如何修改
```htmlembedded=
<div class="header"></div>
```
```javascript=
//使用 querySelector 選取到 class
const header = document.querySelector('.header');
//針對該 class 內去增加 HTML 網頁結構,結構內容為自行組出的字串資料(建議使用反引號``包覆)
header.innerHTML = `<h1 class="title">標題1</h1>`;
```
---
### setAttribute、getAttribute 實作
**知識點:**
**setAttribute、getAttribute**
我們可以透過 setAttribute 來設定指定元素上的屬性
```htmlembedded=
<a href="#"></a>
```
```javascript=
//先透過 querySelector 選取 a Element
const myLink = document.querySelector('a');
//設定該 Element 的 href 屬性
myLink.setAttribute("href","https://www.hexschool.com");
//設定該 Element 的 class 屬性
myLink.setAttribute("class","red");
```
我們可以透過 getAttribute 來取出指定元素上的屬性
```htmlembedded=
<a href="https://www.hexschool.com" class="red"></a>
```
```javascript=
//先透過 querySelector 選取 a Element
const myLink = document.querySelector('a');
//取出該 Element 的 href 屬性
console.log(myLink.getAttribute("href"));//"https://www.hexschool.com"
//取出該 Element 的 class 屬性
console.log(myLink.getAttribute("class"));//"red"
```
---
### 表單欄位取值
**知識點:**
**.value 取值**
**addeventListener**
我們可以透過 .value 來取出表單元素 Elements ,但要注意<span class="blue">取出的值都會是"字串"</span>。
input 欄位取值示範:
```htmlembedded=
<input type="text" class="txt" value="你好棒!">
```
```javascript=
//先透過 querySelector 選取 class txt
const txt = document.querySelector(".txt");
console.log(txt.value)//你好棒!
```
select 取值示範:
```htmlembedded=
<select class="list">
<option value="蘋果">蘋果</option>
<option value="水蜜桃">水蜜桃</option>
<option value="西瓜">西瓜</option>
</select>
```
```javascript=
//先透過 querySelector 選取 class list
const list = document.querySelector('.list');
console.log(list.value)//蘋果
list.value = "水蜜桃";
```
可透過 addeventListener 監聽網頁 Event 事件
```htmlembedded=
<input type="button" class="btn" value="點擊">
<h1></h1>
```
```javascript=
//先透過 querySelector 選取 class btn
const btn = document.querySelector('.btn');
//先透過 querySelector 選取 h1 Element
const title = document.querySelector('h1');
//監聽 click 事件,點擊了按鈕,就會觸發函式的內容
btn.addEventListener("click",function(e){
title.textContent = "你被點擊了!!";
})
```
---
### e.target 搭配 nodeName 節點
**知識點:**
**event**
**e.target、nodeName**
我們可以透過 event 來得知目前 DOM 所發生的事件,如點擊按鈕、按鍵盤等,可以與 addEventListener() 搭配使用,以下為示範:
監聽使用者 click 點擊事件
```htmlembedded=
<button type="button">送出</button>
```
```javascript=
//先透過 querySelector 選取 button
const button = document.querySelector("button");
//監聽使用者點擊就會執行大括號的內容
button.addEventListener('click',function(e){
console.log('123')//點擊按鈕就會印出 123
})
```
監聽使用者 keydown 鍵盤事件
```htmlembedded=
<input type="text">
```
```javascript=
//先透過 querySelector 選取 input
const input = document.querySelector("input");
//監聽使用者按鍵盤就會執行大括號的內容
input.addEventListener('keydown',function(e){
console.log(e.key)
})
```
e.target 會指向目前選取到的 DOM 物件,可以搭配 nodeName 去得知目前點選的節點名稱,以下為示範:
情境:判斷是否點擊到按鈕
```htmlembedded=
<ul class="list">
<li>內文</li>
<li>內文<button type="button">按鈕</button></li>
<li>內文</li>
</ul>
```
```javascript=
//先透過 querySelector 選取 class list
const list = document.querySelector(".list");
//監聽使用者點擊就會執行大括號的內容
list.addEventListener("click", function (e) {
//監聽使用者點擊到的是否為 <button></button> 按鈕
if (e.target.nodeName === "BUTTON") {
console.log("123");
}
});
```
---
### 取消表單預設效果
**知識點:**
**preventDefault**
**表單預設行為**
取消 HTML 標籤的預設行為,以下為示範:
```htmlembedded=
<a class="myLink" href="https://www.hexschool.com/">連結</a>
```
```javascript=
//先透過 querySelector 選取 class myLink
const myLink = document.querySelector(".myLink");
//監聽使用者點擊就會執行大括號的內容
myLink.addEventListener('click',function(e){
e.preventDefault();//阻止 a 標籤默認行為,所以不會轉址
console.log("有被點擊到");
})
```
表單預設行為
如果使用 <input type="submit"> submit ,或是使用 <button></button> 但不指定 type 屬性時預設也會是 submit,而 submit 會將表單提交到伺服器。
我們通常不會使用這個方式提交表單給伺服器,所以會使用 preventDefault 取消它的預設行為,範例如下
```htmlembedded=
<form action="#">
帳號:
<input type="text" name="email">
<br>
密碼:
<input type="text" name="passward">
<input type="submit" value="送出">
</form>
```
```javascript=
//先透過 querySelector 選取 form
const form = document.querySelector("form");
//監聽使用者點擊就會執行大括號的內容
form.addEventListener("click", function (e) {
e.preventDefault();//阻止 submit 屬性默認行為,所以不會提交資料
});
```
---
### 陣列 forEach 寫法
**知識點:**
**forEach() 是陣列的方法**
**forEach 寫法介紹**
**搭配 if,篩選出陣列裡面有幾個偶數**
**forEach 讀取資料**
forEach() 是陣列的方法,會將陣列內的每個值都遍歷。
可以帶入三個參數(參數名稱可自定義):
1. item 當下陣列的值
2. index 迭代資料的索引值
3. array 執行的陣列本身
forEach 寫法介紹
```javascript=
let data = [30,40,50];
data.forEach(function(item,index,array){
console.log(item,index,array);
})
```
forEach() 內可以搭配 if ,並透過在全域宣告變數 total ,累加計算陣列內偶數數字數目
```javascript=
let data = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let total = 0;
data.forEach(function (item, index, array) {
if (item % 2 == 0) {
console.log(item)//2,4,6,8
total += 1;
}
});
console.log(total);//4
```
如果陣列內有多筆物件,可以透過以下方法取出物件內的值
```javascript=
let hexSchoolDiscord = [
{
channelName: "六角筆記王",
teacher: "廖洧杰",
teachingAssistant: "Vivian"
},
{
channelName: "js-必修篇",
teacher: "廖洧杰",
teachingAssistant: "艾草"
}
];
hexSchoolDiscord.forEach(function (item) {
console.log(item.channelName);
console.log(item.teachingAssistant);
});
```
---
### 如何整合 innerHTML 資料
**知識點:**
**整合 innerHTML 資料**
**重要觀念釐清**
可以透過 forEach 與 innerHTML 整合,一次渲染多筆資料在網頁上,以下為示範:
```htmlembedded=
<ul class="list"></ul>
```
```javascript=
let data = [
{
name: "艾草",
stir: true
},
{
name: "Vivian",
stir: false
},
{
name: "鵬聖",
stir: true
},
{
name: "雅萱",
stir: true
}
];
//透過 querySelector 選取 class list
const list = document.querySelector(".list");
//透過在全域宣告 str 累加內文
let str = "";
data.forEach(function (item) {
//判斷是否會攪拌
if (item.stir) {
str += `<li>會攪拌咖哩飯的人有${item.name}</li>`;
} else {
str += `<li>不會攪拌咖哩飯的人有${item.name}</li>`;
}
});
//將結果透過 innerHTML 的方式渲染在網頁上
list.innerHTML = str;
```
**重要觀念釐清**
放至 forEach 內時 innerHTML ,其實是不斷的被執行的,而放置於迴圈外 innerHTML 僅會執行一次,可以更節省效能。
---
### 網頁請求狀態碼
**知識點:**
**AJAX - 網路請求**
**網頁請求狀態碼**
**查看網頁請求狀態碼**
可按照底下步驟於 Google Chrome 網路瀏覽器上查看網頁請求狀態碼:
1. 右鍵點擊後選取檢查
2. 選取 Network

**網頁請求狀態碼**
我們可以從網頁請求 HTTP 狀態碼看出是否有成功發送請求,以下列出幾種常見的 HTTP 狀態碼訊息:
* **成功回應:200~209**
+ 200 OK:請求成功。
* **重定向:300~399**
+ 304 Not Modified :已經有載入過,不會在跟伺服器要資料,會使用暫存的檔案。(資源與之前相較未修改,無須重新傳輸)
* **用戶端錯誤 :400~499**
+ 404 Not Found :伺服器找不到請求的資源(找不到檔案)。
* **伺服器端錯誤 :500~599**
+ 500 Internal Server Error :伺服器端發生未知或無法處理的錯誤(接後端資訊時,可能會遇到)。
相關網路請求代碼:
* **101 Switching Protocols**
+ 已經了解user的請求,並通過Upgrade訊息頭通知使用者採用相應的協定來完成請求。
同學也可以參考此篇 MDN 文章:[HTTP 狀態碼](https://developer.mozilla.org/zh-TW/docs/Web/HTTP/Status)了解其它的狀態碼。
---
### axios-get
**知識點:**
**axios 環境安裝**
**axios-嘗試串接外部資料**
透過 axios 套件連結 CDN 的方式,載入套件,並將程式碼放置於個人 JavaScript 檔案上方:
CDN 連結:
```jsx=
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
```
連結放置處:
```HTML=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 將 axios 套件 CDN 放置於個人 JavaScript 檔案上方 -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">
</script>
<script src="all.js"></script>
</body>
</html>
```
**axios-嘗試串接外部資料**
`axios.get` 範例程式碼:
```jsx=
axios.get('放入想撈取的 JSON 連結')
.then(function (response) {
//回傳的結果
console.log(response);
//抓回來的 JSON 資料
console.log(response.data);
//回傳的狀態碼
console.log(response.status);
});
```
---
### 函式處理 axios-非同步
**知識點:**
**axios-非同步觀念**
**透過函式設計處理非同步**
**axios-非同步觀念**
執行 AJAX 發送網路請求後,須等待對方回傳資料,在對方尚未回傳資料時,會繼續往下執行程式碼,等對方回傳後再回去執行 .then 函式大括號的內容。
```jsx=
let ary = [];
//發送請求
axios.get('https://hexschool.github.io/ajaxHomework/data.json')
.then(function (response) {
//等待對方回傳資料後執行
ary = response.data;
console.log(ary)//印出 response.data 回傳結果
});
//先執行,所以會印出空陣列
console.log(ary)//[]
```
**透過函式設計處理非同步**
**函式處理非同步好處:** 可以確保資料有回傳後才執行函式。
```jsx=
let ary = [];
axios.get('https://hexschool.github.io/ajaxHomework/data.json')
.then(function (response) {
ary = response.data;
console.log(ary)//印出 response.data 回傳結果
//資料回傳後,才去呼叫函式
renderData();
});
function renderData() {
console.log(ary); //印出 response.data 回傳結果
}
console.log(ary);//[]
```
---
### 四種常見的 POST 請求 content-type 介紹
**知識點:**
**四種常見的 POST 請求 content-type**
1. **application/x-www-form-urlencoded**
2. **application/json**
3. **multipart/form-data**
4. **text/plain**
想傳送資料給對方伺服器時,可以透過 POST 方法發送網路請求,發送時也需要讓對方知道我們傳過去的檔案格式會是什麼。
所以我們會透過 headers 中的 Content-Type 告知對方我們要傳送的格式。
* **application/x-www-form-urlencoded**
這種方法是屬於 <form> 表單的原生提交方式:
<form> 標籤的屬性會包含 method 、method 可以使用 get 、 post 發送請求,當指定 post 請求後, <form> 標籤的 enctype 的屬性值會默認使用此方式提交:
```htmlembedded=
<form action="/action_page_binary.asp" method="post" >
<label for="fname">First name:</label>
<input type="text" id="fname" name="fname"><br><br>
<label for="lname">Last name:</label>
<input type="text" id="lname" name="lname"><br><br>
<input type="submit" value="Submit">
</form>
```
以上範例程式碼取自 w3c ,如果想更了解 enctype 屬性,請點選 [enctype Attribute](https://www.w3schools.com/tags/att_form_enctype.asp)。
* **application/json**
目前使用到的 API 都是使用這種 Content-Type ,基本上就是透過 JSON 格式來傳遞參數資料。
透過 axios 套件發送網路請求時,默認的 Content-Type 也是此種類型。
* **multipart/form-data**
如果我們想要上傳 「檔案、圖片、影片」 等,就必須使用這種 Content-Type。
當我們使用表單標籤時,可以透過指定 enctype 屬性為 multipart/form-data 的方式來操作。
```htmlembedded=
<form action="/action_page_binary.asp" method="post" enctype="multipart/form-data">
<label for="fname">First name:</label>
<input type="text" id="fname" name="fname"><br><br>
<label for="lname">Last name:</label>
<input type="text" id="lname" name="lname"><br><br>
<input type="submit" value="Submit">
</form>
```
此為比較進階的 post 用法,如果想更了解 form-data ,請點選此篇 [文章](https://blog.kalan.dev/2021-03-13-html-form-data/)。
關於 form 表單的 post 方法想玩玩看嗎?請點選此 👉 [連結](https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_form_enctype) 也可以移除 enctype 屬性來觀察默認的 Content-Type : x-www-form-urlencoded 編碼方式。
* **text/plain**
基本上就是純文本格式。
---
### data- 屬性妙用
**知識點:**
**data- 屬性妙用**
**補充另一個取值的方式: dataset**
`data-"自定義名稱"`,可以拿來埋各種資料:
HTML:
```html=
<input type="text" class="txt" placeholder="請輸入待辦事項">
<input type="button" class="save" value="儲存待辦">
<ul class="list">
<li>123
<input class="delete" type="button" data-num="1" value="刪除待辦">
</li>
</ul>
```
接下來可以透過 getAttribute 取值:
JavaScript:
```jsx=
const list = document.querySelector(".list");
list.addEventListener("click", function (e) {
if (e.target.getAttribute("class") !== "delete") {
return;
}
let num = e.target.getAttribute("data-num");
console.log(num);
});
```
補充另一個取值的方式: **dataset**
```jsx=
const list = document.querySelector(".list");
list.addEventListener("click", function (e) {
if (e.target.getAttribute("class") !== "delete") {
return;
}
let num = e.target.dataset.num;
console.log(num);
});
```
此種方法也能順利取值 dataset . 的後方請帶入 `data-"自定義名稱"` 的自定義名稱,因為這邊 HTML 自定義名稱為 num ,所以是使用 `dataset.num` 的方式。
需注意的是 假設你的 data 名稱為 `data-xxx-xxx` 在使用 dataset 獲取時需改成小駝峰寫法,舉例如下:
```htmlmixed=
<div data-todo-item="123">
123
</div>
```
```jsx=
<script>
const item = document.querySelector('div').dataset.todoItem;
console.log(item)
</script>
```
---
### 陣列 map 搭配箭頭函式寫法
**知識點:**
課程中使用陣列方法 map 的箭頭函式寫法,這邊以 todolist 較常用到的組字串 forEach 舉例:
**原本的寫法:**
```jsx=
data = [10, 20, 30];
total = 0;
data.forEach(function (item) {
total += item;
});
console.log(total);//60
```
**箭頭函式的寫法:**
function 拿掉,並在參數後補上 => 符號,就完成囉。
```jsx=
data = [10, 20, 30];
total = 0;
data.forEach((item)=> {
total += item;
});
console.log(total);//60
```
雖然一個參數的情況下可以不用在參數外加 () 小括號,但兩個參數以上就會報錯,所以還是建議不管有幾個參數都習慣性加上小括號唷!
**箭頭函式再精簡:**
把 {} 大括號拿掉後,縮成一行也是可以辦到的唷!
此種更精簡寫法適用於函式內程式碼不多時,程式碼較多的情況不建議使用。
```jsx=
data = [10, 20, 30];
total = 0;
data.forEach((item)=> total += item );
console.log(total);//60
```
todolist 內會使用到 forEach 整合 innerHTML 去組字串並渲染到網頁上,不熟悉的同學歡迎複習:[ 8/24 (二) - 如何整合 innerHTML 資料](https://hackmd.io/AiqAH3ztSrq58GfGbJ7Tog)。
---
### Date 物件
**知識點:**
> **Date 物件**
補充一個在埋 id 時,很常使用的方法:
Date 物件是基於世界標準時間(UTC) 1970 年 1 月 1 日開始的毫秒數值來儲存時間。
所以可以透過 `new Date().getTime()` 的方式來當成 id 使用。
```jsx=
//建立 Date() 物件後使用 getTime() 取得時間
//getTime() 會取出 (由 1970年1月1日零時零分計起到目前時間)
let id = new Date().getTime();
console.log(id)//1629966889412 (每毫秒都不同,所以歡迎自行貼到 CodePen 觀看)
```
想更了解 Date 物件,歡迎參考此篇[文章](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Date)。
---
### findIndex
**知識點:**
> **findIndex**
透過陣列方法 findIndex 可以獲取符合條件的索引值,如果找不到符合條件的索引值,就會回傳 -1
透過此方式,搭配 splice 方法,就可以刪除特定資料,參考程式碼如下
假設下方是陣列的資料內容:
```javascript=
const orders = [
{
name: "艾草",
id: 123456789
},
{
name: "ViVian",
id: 987654321
}
];
```
使用時需要留意型別,如果型別錯誤將找不到該筆資料
(HTML 內取出的皆為字串型別)
```javascript=
// 透過 findIndex 找出符合『 id 為 123456789 』條件的索引值
let index = orders.findIndex((item) => item.id === 123456789 );
console.log(index) // 輸出結果為 0
```
以下是錯誤的寫法:
>假設真的遇到需處理字串的型別
>建議使用雙等於 或是將資料轉換成數字後再做比較
```jsx=
let indexError = orders.findIndex((item) => item.id === "123456789" );
console.log(indexError)// -1 找不到 因為兩者型別不同
```
最終配合使用 splice 方法,透過回傳的索引值去刪除該筆資料即可。
```jsx=
orders.splice(index, 1);
console.log(orders)
```
---
### getElementById 節點
**知識點:**
> **getElementById**
> **classList**
> **closest**
**getElementById**
當要獲取綁定 Id 的元素時,也可以透過 getElementById 來獲取,getElementById 的使用方式如下:
HTML:
```htmlembedded=
<button id="addTodo" type="button">新增</button>
```
```javascript=
// 透過 getElementById 獲取 id 為 addTodo 的元素
const addTodo = document.getElementById('addTodo');
```
如果要選取其他的元素,也可以透過 querySelector 來實現,想更了解 getElementById 的使用方式,歡迎參考此篇[文章](https://developer.mozilla.org/zh-CN/docs/Web/API/Document/getElementById)。
**classList**
classList 可以拿來確認是否包含某個特定 class 類別,與透過 getAttribute("class") 的方式要符合全部 class 類別不同,
我們可以使用 Element.classList.contains('className'),來確認該 Element 是否存在某 className 類別。
完整範例如下:
HTML:
```html=
<button type="button" class="btn btn-outline-primary">按鈕</button>
```
JavaScript:
```jsx=
//透過 querySelector 選取 class btn 這個元素
const btn = document.querySelector('.btn');
//給該按鈕註冊點擊事件
btn.addEventListener('click',(e)=>{
//方法一:透過 getAttribute("class")
if (e.target.getAttribute("class") === "btn") {
console.log("getAttribute 選到按鈕了");
}
//方法二:透過 classList.contains
//如果點擊到的元素 classList 內有包含 btn
if(e.target.classList.contains("btn")){
console.log('classList.contains 選到按鈕了')
}
})
```
原因是透過 getAttribute("class") 的方式選取 class 會回傳所有 class
同學可嘗試加入 console.log(e.target.getAttribute("class"))
就會發現輸出結果為 "btn btn-outline-primary"
而我們設置的判斷條件則是只需要判斷某一個 class 是否存在
此時就比較適合使用 classList.contains 方法判斷是否包含某一個特定樣式
想了解更多關於 classList 可以使用的方法,歡迎參考此篇 👉 [文章](https://developer.mozilla.org/zh-TW/docs/Web/API/Element/classList)。
**closest**
當在複雜 HTML 結構中想透過 e.target 選取某個 Element ,卻都只能選到它的子層時,可以透過 closest 去取到自己想要的 Element ,
透過 closest 的方法,能很方便的取到自己想要的父層 Element ,範例如下:
HTML:
```html=
<ul class="list">
<li>
<input type="text">
<span>123456789</span>
<button type="button">按鈕</button>
</li>
</ul>
```
JavaScript:
```jsx=
//透過 querySelector 選取 class list
const list = document.querySelector(".list");
//註冊監聽 list 的點擊事件
list.addEventListener("click", (e) => {
//單純監聽點擊到的元素本身 e.target
console.log(e.target);
//透過 closest 方法並於括號內透過字串形式的方式,放入想選取到的標籤名稱
console.log(e.target.closest("li"));
});
```
分別點選 input 、 span 、 button 的印出結果如下:
(一)單純使用 e.target

(二)使用 e.target.closest("li")

想了解更多關於 closest 可以如何使用,歡迎參考此篇 👉 [文章](https://developer.mozilla.org/zh-CN/docs/Web/API/Element/closest)。
---
### querySelectorAll
**知識點:**
> **querySelectorAll**
> **classList**
**querySelectorAll**
透過 querySelectorAll 可以選取多個元素,會回傳 nodeList ,操作上類似陣列,且 querySelectorAll 也可以使用陣列方法的 forEach ,參考如下:
HTML:
```html=
<ul class="list">
<li>123</li>
<li>456</li>
<li>789</li>
</ul>
```
JavaScript:
```jsx=
const list = document.querySelectorAll(".list li");
list.forEach((item) => {
console.log(item);
});
```
印出結果:

**classList**
可以透過 Element.classList 來新增、刪除或修改某 DOM 元素的 class 類別,範例如下:
HTML:
```html=
<button type="button" class="btn btn-outline-primary">按鈕</button>
```
JavaScript:
```jsx=
//透過 querySelector 選取 class 為 btn 的元素
const btn = document.querySelector('.btn');
//透過 classList 的 remove 方法移除 btn 的 btn-outline-primary 這個 class 類別
console.log(btn.classList.remove('btn-outline-primary'));
console.log(btn);// 輸出結果為 <button type="button" class="btn">按鈕</button>
//透過 classList 的 add 方法新增 btn的 class 類別 btn-outline-primary
console.log(btn.classList.add("btn-outline-primary"));
console.log(btn);// 輸出結果為 <button type="button" class="btn btn-outline-primary">按鈕</button>
```
---
### 鍵盤事件 - keyup
**知識點:**
> **鍵盤事件 - keyup**
**鍵盤事件 - keyup**
鍵盤事件 keyup 可以拿來偵測是否按下特定鍵盤,而 keyup 的觸發時機為當你按下特定鍵盤又放開的那刻:
```html=
<input type="text">
```
```jsx=
//透過 querySelector 選取 input 欄位
const input = document.querySelector('input');
//註冊監聽 input 欄位的 "keyup" 事件
input.addEventListener("keyup", function (e) {
console.log(e);
});
```
當我點擊 Enter 鍵觸發該 "keyup" 事件時,可以觀察到 Event 包含:

該 "keyup" Event 內相當多的屬性,如果我們希望點擊到 Enter 時,可以觸發對應事件,可以透過以下方式:
```jsx=
//註冊監聽 input 欄位的 "keyup" 事件
input.addEventListener("keyup", function (e) {
//如果屬性的 key 值為 "Enter"
if (e.key === "Enter") {
//符合條件就執行大括號內程式碼
console.log('我鍵盤按了 Enter ')
}
});
```
想多了解鍵盤事件怎麼觸發,可以點擊此 [CodePen 檔案](https://codepen.io/denilsonsa/pen/epmoma)。
---
### .match()
**知識點:**
> **.match()**
> **.match() 搭配 filter**
**.match()**
`str.match()`括號內通常會放入一個正規表達式,當該字串與正規表達式的匹配結果符合時,它將回傳一個新陣列,而陣列內會放入符合的結果,範例如下:
```jsx=
//要比對的字串
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
//要找出範圍 A-E
//g:比對該字串所有位置
//i:不去區分大小寫
//宣告一個變數賦予正規表達式
var regexp = /[A-E]/gi;
var matches_array = str.match(regexp);
console.log(matches_array);
// ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']
```
以上範例程式碼取至 MDN,如果想更瞭解正規表達式歡迎點選 👉 [文章](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Regular_Expressions)。
**.match() 搭配 filter**
`.match()`不僅能搭配正規表達式,還可以搭配 filter 來優化搜尋功能,範例如下:
HTML:
```html=
<!-- <input type="search"> 此 type 可專門拿來搜索-->
<h3>.match() 搭配 filter 搜尋</h3>
<input type="search">
<button type = "button">按鈕</button>
<ul></ul>
```
JavaScript:
```jsx=
const list = document.querySelector("ul");
const button = document.querySelector("button");
let data = [
{
作物名稱: "椰子"
},
{
作物名稱: "釋迦"
},
{
作物名稱: "藍莓-進口藍莓"
}
];
//初始化,先將 data 的作物名稱渲染於畫面上
function renderData(showData) {
let str = "";
showData.forEach((item) => {
str += `<li>${item.作物名稱}</li>`;
});
list.innerHTML = str;
}
renderData(data);
//監聽 button 按鈕的點擊事件
button.addEventListener("click", (e) => {
//透過 querySelector 選取 input 欄位
const input = document.querySelector("input");
let filterData = [];
//透過 data 去跑 filter 並將結果賦予給 filterData
filterData = data.filter((item) => {
//回傳 .match 符合的匹配結果
return item.作物名稱.match(input.value);
});
console.log(filterData)
renderData(filterData);
});
```
顯示結果:

歡迎點選此 👉 [CodePen](https://codepen.io/jmkhsutp/pen/ZEypgYm?editors=1010) 玩看看唷!
---
### switch
**知識點:**
> **switch**
> **sort()**
**switch**
`switch` 後的小括號內會帶入一個表達式,並透過表達式的值去比對底下 case 後帶入的值是否符合該表達式回傳的值,符合的情況就會去執行 case 底下的條件,而每個 case 執行完後必須帶入 break ,才能終止程式碼繼續往下一個 case 執行,語法如下:
語法:
```jsx=
switch (expression) {
case value1:
//當 expression 的值符合 value1
//要執行的陳述句
break;
case value2:
//當 expression 的值符合 value2
//要執行的陳述句
break;
case valueN:
//當 expression 的值符合 valueN
//要執行的陳述句
break;
default:
//當 expression 的值都不符合上述條件
//要執行的陳述句
break;
}
```
想了解表達式與陳述式為何,歡迎參考此篇 👉 [文章](https://wcc723.github.io/development/2020/09/17/js-expression/)
透過簡單的範例讓同學更了解 switch :
HTML:
```jsx=
<select>
<option value="蘋果">蘋果</option>
<option value="香蕉">香蕉</option>
<option value="水蜜桃">水蜜桃</option>
<option value="雞腿飯">雞腿飯</option>
</select>
```
JavaScript:
```jsx=
let select = document.querySelector("select");
//監聽 select 的 "change" 事件
select.addEventListener("change", (e) => {
//比對是否為 change 更換到的元素的 value
switch (e.target.value) {
case "蘋果":
console.log(e.target.value);//"蘋果"
console.log("我是蘋果");
break;
case "香蕉":
console.log(e.target.value);//"香蕉"
console.log("我是香蕉");
break;
case "水蜜桃":
console.log(e.target.value);//"水蜜桃"
console.log("我是水蜜桃");
break;
default:
console.log(e.target.value);//"雞腿飯"
console.log("我不是蘋果/香蕉/水蜜桃");
break;
}
});
```
結果歡迎點選此 [CodePen](https://codepen.io/jmkhsutp/pen/OJgbRoQ?editors=1011) 嘗試看看,可以透過 Console 查看 Change 後的結果哦!
**sort()**
陣列方法 `sort()` 可以用來重新排列陣列中的元素,並返回原陣列。
`sort()` 可帶入參數 `compareFunction` ,且會根據 `compareFunction` 函式內帶入參數的比較結果,去進行排序。
如果使用 `compareFunction` 參數,並定義該函式內有參數 `a` 和 `b` 為被比較之兩元素,則:
- 若 `a` - `b` < 0, `a` 排在 `b` 前面。
- 若 `a` - `b` = 0,則 `a` 與 `b` 皆不會改變彼此的順序,但會與其他全部的元素比較來排序。
- 若 `a` - `b` > 0 ,則 `b` 排在 `a` 前面。
所以,比較函式會是以下形式:
```jsx=
let arr = [5, 2, 3, 4, 1, 7, 20, 10, 90, 6];
//compareFunction
arr.sort(function (a, b) {
return a - b;
});
// arr = [1, 2, 3, 4, 5, 6, 7, 10, 20, 90];
```
想了解更多關於陣列方法 sort() ,歡迎參考此篇 👉 [文章](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)。