---
# System prepended metadata

title: 瀏覽器內的 JavaScript
tags: [程式導師, JavaScript]

---

# 瀏覽器內的 JavaScript

###### tags: `程式導師` `JavaScript`

## 瀏覽器與 JavaScript 的溝通

### 基本觀念

- JS script 放置的位置很多，但會受到讀取網頁元素的順序影響，因不同的擺放位置而有不同結果。
- script 可以跟 HTML 寫在同個檔案內，也能獨立成一個檔案，再引入 HTML。

```htmlmixed
<!--將 JS script 寫在 HTML 內-->
<script>
    //js script
</script>

<!--在 HTML 引入 JavaScript script-->
<script src=".../style.js"></script>
```

解決 JS 放 body 前，選不到的問題，可以先寫以下程式碼，讓網頁元素載入後才開始執行 JS。

```javascript
documemt.addEventListener('DOMContentLoaded', function(){
    //要執行的內容
})
```

#### DOM
全名是 Document Object Model，簡而言之，是將 Document 轉換為有結構的物件，成為 JavaScript 跟瀏覽器溝通的橋樑。

## 介面：如何改變介面

### 選元素

1. `getElementsByTagName('div')` 選取所有 HTML tag = div 的元素
2. `getElementsByClassName('block')` 選取所有 class=block 的元素
3. `getElementById('name')` 選取 id=name 的元素
4. `querySelector('.block')` 選取一個符合 CSS 選擇器內容的元素
5. `querySelectorAll('.block')` 選取所有符合 CSS 選擇器內容的元素

使用 querySelector 跟 querySelectorAll，只要熟悉 CSS 選擇器的寫法，就能輕易指定想要的網頁元素，用起來方便，之後可以多使用這個選擇方法。

### 改 CSS 樣式 `style`

`<element>.style.<CSS 屬性> = <value>`

1. 選元素 `const elements = querySelector('.block')`
2. 指定改變的性質 `elements.style.padding = '10px'`

上述方式可以讓 class = block 的元素 padding 變成 10px。
其他寫法：

- `elements.style['padding-top'] = '10px'` 
- `elements.style.paddingTop = '10px'`

### 改變 Class `classList`

`<element>.classList.<add/remove/toggle>('<className>')`
1. 選元素 `const elements = querySelector('.block')`
2. 為元素新增 Class `elements.classList.add('active')`
3. 為元素刪除 Class `elements.classList.remove('active')`
4. 根據現況新增／刪除 Class `elements.classList.toggle('active')`

toggle 類似開關，會根據現在的狀況調整觸發後的內容，如果本來有，就會改成沒有，如果本來沒有，會改成有。

### 改變內容

1. 選元素 `const elements = querySelector('.block')`
2. 選擇改變的範圍：只有文字 `elements.innerText = '改成這個文字'`
3. 選擇改變的範圍：標籤內的內容 `elements.innerHTML`
4. 選擇改變的範圍：連標籤自己也被圈選 `elements.outerHTML`

```htmlmixed
<div class='block'>
    <p>This is a sample</p>
</div>

<script>
    const elements = querySelector('.block');
    console.log(elements.innerText);
    //This is sample
    
    console.log(elements.innerHTML); 
    //<p>This is sample</p>
    
    console.log(elements.outerHTML);
    //<div class='block'>
    //   <p>This is a sample</p>
    //</div>
</script>
```

### 操作 DOM：插入／刪除元素

1. 選取要增刪的目標元素的父層
2. removeChild, appendChild

```htmlmixed
<div class='block'>
    <div> This is a Test</div>
</div>

<script>
    const element = document.querySelector('block');
    element.removeChild(document.querySelector('div'));
    //移除 block 內的 div
    
    const newItem = document.createElement('div');
    element.appendChild(document.querySlector(newItem));
    //新增元素前，要先給個元素，再 append 到既有元素上
    
    //新增純文字內容，方法一
    const element = document.querySelector('block');
    newItem.innerText = '123';
    element.appendChild(newItem);
    
    //新增純文字內容，方法二
    const newText = document.createTextNode('123');
    element.appendChild(newItem);
    
</script>
```

## 事件：如何監聽事件並作出反應

### 事件監聽 Event Listener

```javascript
// 寫法 1
element.addEventLisitener('click', onClick)

function onClick() {
    //執行
}


//寫法 2（常見）
element.addEventListener('click', function(){
    //執行
})
```

#### Callback function

一種點餐後收到震動通知器的概念，當觸發了某條件後，才會執行。

### 表單處理

阻止送出表單資訊，通常用來提示帳號密碼錯誤、阻止輸入特定鍵。
```javascript
element.addEventListener('click', function(e){
    e.preventDefault()
})
```

## 資料：如何跟伺服器交換資料

### 在瀏覽器上儲存資料

- Cookie
- Local Storage（推薦）
- Session Storage

#### Cookie

被自動帶到 server 的小型文字檔

#### Local Storage（推薦）

以此種方式儲存的內容只能是字串
儲存方式是 key:value 形式

```javascript
localStorage.setItem('text', value)
```

#### Session Storage

用法跟 local storage 一樣，儲存時間最短，換分頁就沒了。

### 網頁與伺服器溝通

**node.js 發 request vs 在瀏覽器發 request 的差別**

兩者的差別在於「有沒有人限制你」，在瀏覽器上的 js 與 server 間有透過瀏覽器（省略作業系統），所以會受到瀏覽器版本的限制，需要學習其他規則。

傳資料的方式
1. form（只透過 HTML 完成資料傳送）缺點是每次 request 就要換頁，所以會想改用 JS 完成資料傳送，也就是 AJAX
2. AJAX（透過 JS 交換資料），一種統稱，任何能跟伺服器非同步交換資料，就可稱為 AJAX，使用 XMLHttpRequest() 作為資料交換格式。
3. JSON（json with padding）利用 script 不受瀏覽器同源政策影響的特性

**使用 AJAX 拿資料的起手式**
```javascript
const request = new XMLHttpRequest();

// 送出 request 等候回傳，若傳送狀態錯誤，回傳錯誤
request.onload = function () {
    if (request.status >= 200 && request.status < 400){
        console.log(request.responseText);
    } else {
        console.log('error');
    }
}

// 上述程式碼的用 event listener 的寫法
request.addEventListener('load', function () {
    if (request status >= 200 && request status < 400){
        console.log(request.responseText);
    } else {
        console.log('error');
    }
})


// 檢視 request 本身是否有錯
request.onerror = function () {
    console.log('error');
}

// 送出
request.open('GET', 'https://google.com', true);
request.send;
// true 或 false 決定是否要非同步
```


### SOP 與 CORS：瀏覽器對來源的限制

**Same Origin Policy**
同源政策，只有當相同協定、相同 port、相同主機位置的網域，才有辦法越過瀏覽器的存取限制。

> 不受同源政策影響的網頁元素：img、script 的 src。
> AJAX 一定受到同源政策管理。但有例外，就是使用 JSONP 拿資料。

**CORS**
如果要請求的網頁是不同網域，就要看被請求的網站是否有 CORS 跨來源資源共用。也就是被請求的網站伺服器，要在 response header 加上 Access-Control-Allow-Origin。

對來源限制的原因是「安全性考量」

### Client Side Rendering vs.

Client Side 無法直接透過 inspect 知道使用者資料