# [FE102] 前端必備:JavaScript(DOM) ###### tags: `JavaScript` ## JavaScript 的執行環境: 主要是這兩個: 1. node.js 2. 跑在browser上 在不同環境底下,能夠跑的javascript語法不一定都可行 ex: ```javascript= //這個語法就不行,因為拿到request這個module是在node.js裡面特定的 const request = require('request'); request('http://www.google.com', function (error, response, body) { console.error('error:', error); // Print the error if one occurred console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received console.log('body:', body); // Print the HTML for the Google homepage. }) ``` ## console - 在於將( )的內容輸出至主控台 - 利用javascript請瀏覽器執行某些動作時,能夠以js進行操作的零件,就稱為物件. - 為了方便操作,每一個物件都有自己的名稱(詳請可以看p2-13) 主控台的名稱是"console" ```javascript= console.log('鸚鵡學舌') ``` console:物件/log:方法/'鸚鵡學舌':參數 ## document 網頁內容的名稱是"document" ### getElementById ```javascript= document.getElementById('class').textContent =new Date(); //document:物件 //getElementById:方法 ``` 其餘方法抓取document的方法 ### queryselector ```javascript= document.queryselector('option[value="index.html"]') ``` option[value="index.html"] :屬性選擇器 要取得value為index.html的元素 ==注意:只有第一個元素會被選取== ### queryselectorAll * 利用html的class屬性來取得多個元素,並全部都設定相同的事件 * 資料抓出來會是陣列,可以搭配for迴圈使用 ```javascript= var thumb = document.queryselectorAll('.thumb') for(var i=0;i<thumb.length;i++){ thumb[i].onclick= function(){ document.getelementbyid('bigimg').src=this.dataset.image } } ``` 補充說明 ``` this:代表發生事件的元素本身(為onclick事件) data-*:屬性 (此自定為data-image) 讀取此屬性: this.dataset.image(自訂的名稱) ``` [codepen範例](https://codepen.io/norriswu/pen/NJNrOW) *** ### textContent 物件屬性代表該物件目前的狀態,可以執行讀取或是改寫 此段翻成中文為 **將class的內容設為new Date()** createElement(標籤名稱) appendChild(想添加的子元素,並往下添加) ```javascript= for(var i=0;i<todo.length;i++){ var li= document.createElement('li'); li.textContent=todo[i] document.getElementById('#list').appendChild(li) } ``` ## window ```javascript= var answer = window.prompt('是否要閱讀遊戲說明') console.log(answer) ``` 這是window物件用的方法,在對話框輸入什麼,控制台就會顯示什麼 ## DOM是什麼? 直白: browser提供了一個橋樑,讓我門用javascript去改變畫面 Huli的說法: HTML的階層關係,可以轉換成類似物件的形式,也可以參考如下圖片. ![](data:image/png;base64,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) ## `<script> `標籤放的位置很重要 因為只要碰到 JavaScript,停下來執行它,所以通常會把 `<script>`放在`</body>`前!因為網頁的渲染是從到上下的,為了確保 DOM tree 建完後, JavaScript 透夠 DOM 進行運作/溝通。 ```htmlmixed= <body> ... <script src="./main.js"></script> </body> ``` # 選到想要的元素 ## getElementsByTagName() 注意's',因為tag不會只有一個. > 這比較少用,這年頭哪一個標籤沒有用class的 ## getElementsByClassName() 注意前面不用加上'.',因為已經要傳class了,前面加了'.'還是class. ```htmlmixed= <div class="test">123</div> <div class="test">123</div> <div class="test">123</div> ``` ```htmlmixed= var allTest = document.getElementsByClassName('test'); allTest[1].style.color = 'red'; // 得 第二行為紅色 123 // 同時示範改變css的方法(但是比較不常在裡面直接加上style的方法) ``` ## getElementById() 不用加上's',因為他是'ID' > 用法同上 ## querySelector('') 注意因為他是選擇器,所以要加上<em>前綴號</em> 只會回傳第一個匹配到的元素 ```htmlmixed= <div class = "test"> <p>123</p> <p>321</p> </div> ``` ```htmlmixed= var test = document.querySelector('.test > p') test.style.color = 'blue'; // 得 藍色 123 ``` ## querySelectorAll('') 他會選到所有這個元素的節點. ## 動態增加或是移除class (ClassList作法) > 說真的這個東西我怎麼一點印象都沒有,我有印象的是addClass 但那個是jquery的用法咧... ```htmlmixed= <style> .active{ background: red; } </style> <div class = "test"> <p>123</p> <p>321</p> </div> ``` ```javascript= const element = document.querySelector('.test') //注意底下的語法 element.classList.add('active') element.classList.remove('active') element.classList.toggle('active') //再貼一次就又有了 element.classList.toggle('active') ``` ## 改變內容 > 我只記得innerHTML, innerText一點印象都沒有 更不用提outerHTML, outerText... ```htmlmixed= <div id="block"> yo <a><b>hello</b></a> </div> <script> const element = document.querySelector('#block a') console.log(element.innerText)//標籤中的字印出來 // hello console.log(element.innerHTML)//標籤中的東西印出來 // <b>hello~</b> console.log(element.outerText)//標籤外的字印出來 // hello(少用) console.log(element.outerHTML)//整段都給出來 // <a><b>hello~</b></a>(少用) </script> ``` ### 補充: 先來看圖 ![](https://i.imgur.com/S1AOAa0.png) > 其實上面範例就看的出來說text/html的差異,我這邊再補充一點 ```javascript= const element = document.querySelector('#block > a') element.innerHTML= '<h1>1234</h1>' // 把html內籤在程式碼裡面了 element.innerText= '<h1>1234</h1>' // 他最後會顯示出<h1>1234</h1> ``` ## 新增node和刪除node ```htmlmixed= //刪除元素 <div id="block"> yo <a>hello~</a> </div> <script> const element = document.querySelector('#block') element.removeChild(document.querySelector('a')) </script> ``` ```htmlmixed= //新增節點裡面的文字 <script> const element = document.querySelector('#block') const item = document.createTextNode('123') element.appendChild(item) </script> ``` ```htmlmixed= //新增節點 <script> const element = document.querySelector('#block') const item = document.createElement('div') element.appendChild(item) </script> ``` ## callback function(回呼函式) 為執行 addEventListener 背後的概念。其目的就是為了不要讓其他事情被阻塞 (block),而延伸出來的方式。概念有點像是美食街的呼叫器,『好了後再叫我』! ```javascript= document.getElementById('btn').addEventListener('click', function() { //程式碼 }) ES6 寫法: document.getElementById('btn').addEventListener(‘click', () => { }) ``` 上面的 function: 等到 click 事件發生後,才呼叫裡面的函式 = callback funciton (同時他也是個匿名函式喔) > 補充 直播課程4-2 @23:09 callback function ```javascript= //以這種方式居多 function callMe(data){ console.log('done') } getData(callMe) function getData(cb){ ...發 request ...response回來 cb(response) } ================= const data = getData() //這一種變數命名方式沒辦法讓getData()這個function //執行需要過長時間的程式 ``` ### 綜合練習 1. 如何監測自己按下的鍵? ```javascript= const element = document.querySelector('input') element.addEventListener('keydown', function(e){ console.log(e.key) }) ``` <mark>2. 透過按鈕更改網頁的背景顏色</mark> 基本上這題是要能夠點擊按鈕後,切換更改網頁的顏色,一般按按鈕改顏色我就不多做示範了 在html裡面已經寫好這個style了 ```htmlmixed= <style> .active{ background: red; } </style> ``` ```javascript= <script> const btn = document.querySelector('.btn') btn.addEventListener('click', ()=> { document.querySelector('body').classList.toggle('active') }) </script> ``` > 重點是他透過classList增加了active的樣式,在透過toggle屬性做到開闔 讓我想到了jquery,看了下前面的示範好像沒啥了不起的. ## form表單中,停止驗證 > 其實這個以前也學過了,當時我還記得叫做change的作法,現在還真的忘的差不多了 底下範例示範的是當password1 不等於 password2 時的程式碼 ```htmlmixed= <form class="login-form"> <div> username: <input name="username" /> </div> <div> password: <input name="password" type="password"/> </div> <div> password again: <input name="password2" type="password"/> </div> <input type="submit"> </form> <script> const element = document.querySelector('.login-form') element.addEventListener('click',function(e){ const input1= document.querySelector('input[name=password]') const input2= document.querySelector('input[name=password2]') if(input1.value !== input2.value) { alert('密碼不同') e.preventDefault() } }) </script> ``` ## 先補獲在冒泡 ``` addEventListener('click', callback , boolen) ``` > 其實這就是addEventListener最後的布林值, 如果要記住的話,捕獲從上到下比較合理,所以是true 而冒泡由下到上,所以是false(預設) 兩個重點: <mark>1. 先捕獲,再冒泡</mark> <mark>2. 當事件傳到 target 本身,沒有分捕獲跟冒泡</mark> ![](https://i.imgur.com/Uvk9Nwd.png) ## 取消事件傳遞 > 那如果我要停止冒泡呢? 我犯了錯不想讓大家知道.... > e.stopPropgation 不過,在這邊依然有一個地方要特別注意。 這邊指的「事件傳遞被停止」,意思是說不會再把事件傳遞給「下一個節點」,但若是你在同一個節點上有不只一個 listener,還是會被執行到。 若是你想要讓其他同一層級的 listener 也不要被執行,可以改用e.stopImmediatePropagation(); ## 取消預設行為 常常有人搞不清楚e.stopPropagation跟e.preventDefault的差別,前者我們剛剛已經說明了,就是取消事件繼續往下傳遞,而後者則是取消瀏覽器的預設行為。 這一篇真的值得一讀在讀 > [延伸閱讀_DOM 的事件傳遞機制:捕獲與冒泡](https://blog.techbridge.cc/2017/07/15/javascript-event-propagation/) ## 新手100%會犯的錯 練習1: 要呼叫自己屬性的按鈕 ```htmlmixed= 通常要存數字,不會用文字,而是用以data開頭的屬性 <div class="outer"> <button class="btn" data-value="1">1</button> <button class="btn" data-value="2">2</button> <button class="btn" data-value="3">3</button> <button class="btn" data-value="4">4</button> <button class="btn" data-value="5">5</button> </div> ``` 方法一 ```javascript= //function是在點擊的那一刻觸發的,迴圈跑完之後i的值是5, 所以會變成5+1=6 const el = document.querySelectorAll('.btn') for(var i=0; i < el.length ;i++) {// 其實改成let i=0 就可以解 el[i].addEventListener('click',function(e){ alert(i+1) }) } ``` 方法二 ```javascript= const el = document.querySelectorAll('.btn') for(var i=0; i < el.length ;i++) {// 其實改成let i=0 就可以解 el[i].addEventListener('click',function(e){ alert(e.target.getAttribute('data-value')) }) } ``` ### 新增一個新按鈕,按了以後會新增btn ```htmlmixed= <div class="outer"> <button class="add-btn">add</button> <button class="btn" data-value="1">1</button> <button class="btn" data-value="2">2</button> </div> ``` ```javascript= const el = document.querySelectorAll('.btn') for(var i=0; i < el.length ;i++) {// 其實改成let i=0 就可以解 el[i].addEventListener('click',function(e){ alert(e.target.getAttribute('data-value')) }) } ``` ```javascript= //因為num會從3開始,前面1,2已經宣告過了 let num =3 document.querySelector('.add-btn').addEventListener('click',function(){ //宣告新按鈕 const btn = document.createElement('button') //因為是空的button,所以要繼續往下設定屬性 btn.setAttribute('data-value', num) //設定完屬性後,裡面應該要再加上內容 btn.innerText= num //下一次的num就會變成這一次的num + 1 num = num + 1 //最後再把他加入到outer的底下 document.querySelector('.outer').appendChild(btn) }) ``` > 但是還是只有前面兩個有eventListener的監聽,後面新產生的button沒有 所以這時候就會提及下一個章節,事件代理 ## 事件代理 event delegation > 1. 常用,因為有效率,不用浪費那麼多資源處理差不多的事情 > 2. 處理動態新增也可以 ```javascript= document.querySelector('.outer').addEventListener('click',function(e){ //看是否有包含btn這個class if(e.target.classList.contains('btn')){ alert(e.target.getAttribute('data-value')) } }) ``` ## 綜合練習 ### 簡易密碼產生器 ```htmlmixed= <div class="section"> <div><label><input type="checkbox" name="en">英文</label></div> <div><label><input type="checkbox" name="num">數字</label></div> <div><label><input type="checkbox" name="sp">特殊符號</label></div> <button class="btn">密碼產生</button> <div class="result"></div> </div> ``` ```javascript= const btn = document.querySelector('.btn') const result = document.querySelector('.result') btn.addEventListener('click',function (){ let availableChar = '';//組成的字串 if(document.querySelector('input[name="en"]').checked == true) { availableChar += 'abcdefghijklmnopqrstuvwxyz' // 26 } if(document.querySelector('input[name="num"]').checked == true) { availableChar += '0123456789' // 10 } if(document.querySelector('input[name="sp"]').checked == true) { availableChar += '!@#%^&*+' // 8 } let outcome = '' //組一個十位數的密碼 for(let i=0; i < 10 ; i++) { //取一個數字讓他可以在0~9之間,後面乘以長度是因為總共加起來有44個隨機數, //若是乘以10,則只會出現英文字 let number = Math.floor(Math.random()*availableChar.length) outcome += availableChar[number] } result.innerHTML=outcome }) ``` ## hoisting 概念如下: ```javascript= function test(){ console.log(a) var a = 10 } test()// undefined 不是not defined ``` > 可以看成這樣 ```javascript= function test(){ var a; console.log(a) a = 10 } ``` > 所以變成變數還沒有宣告 <mark>但是let/const 沒有變數提升的概念這是錯的</mark> ```javascript= function test(){ console.log(a) let a = 10 } test() // not defined ``` 隋堂考試 ```javascript= function test(){ let a = 1 function test2(){ console.log(a) var a = 10 } test2() } test()//undefined. ``` #### function執行有hoisting. 可以先執行在宣告function. ### 出自第十五週網站前後端開發基礎測試Q10:+1: 小明在執行程式的時候出現了一個錯誤:Uncaught TypeError: Cannot read property 'selfId' of undefined,但百思不得其解,不知道是哪裡出了問題,以下是出錯的「部分」程式碼: ```javascript= const result = list.filter(item => item.parent.id === matches[0].parent.id && item.parent.name === matches[0].parent.name && item.selfId === homeData.selfId ).sort( (a, b) => a.typeId - b.typeId ); ``` 根據你的推理,會出現這個錯誤的原因是什麼? 點我看 Q10 解答 這一題是我覺得最好玩的一題,考驗你對 JS 錯誤訊息的理解。 你可能會認為說:「不對吧,你很多資訊都沒有給齊,這題怎麼解?狀況很多吧!」 讓我來幫你解惑,首先你可能會答說:「homeData 上面可能沒宣告」,但如果是這種狀況,錯誤訊息就會是 ReferenceError: homeData is not defined,所以這種狀況可以排除,代表 homeData 一定有宣告。 同理,matches 也一定有宣告,不然錯誤訊息會不一樣。 再來,錯誤訊息告訴我們說:Cannot read property 'selfId' of undefined,代表我們試圖對一個 undefined 讀取 selfId 這個屬性。 出現 selfId 的是這行:item.selfId === homeData.selfId。 如果 item 是 undefined,前面 item.parent.id 時就會出錯,所以 item 是沒有問題的。 因此,會出現這個錯誤訊息的原因是 homeData 是 undefined。