# 每日任務重點筆記 >[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 ![](https://i.imgur.com/bUANBRN.png) **網頁請求狀態碼** 我們可以從網頁請求 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 ![](https://i.imgur.com/mEjShDV.png) (二)使用 e.target.closest("li") ![](https://i.imgur.com/ujEIVnC.png) 想了解更多關於 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); }); ``` 印出結果: ![](https://i.imgur.com/E8DPe74.png) **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 包含: ![](https://i.imgur.com/oyay5UJ.png) 該 "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); }); ``` 顯示結果: ![](https://i.imgur.com/dmwiB88.png) 歡迎點選此 👉 [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)。