---
# System prepended metadata

title: '[FE102] 前端必備：JavaScript(DOM)'
tags: [JavaScript]

---

# [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。