* JS 基礎知識,規定語法 ECMA 262 標準
* JS Web API,網頁操作的 API W3C 標準
### DOM
* DOM:Document Object Model
* Vue 和 React 框架應用廣泛,封裝了 DOM 操作
#### DOM 節點操作
```javascript
const div1 = document.getElementById('div1') // 元素
const divLIst = document.getElementsByTagName('div') // 集合
const containerList = document.getElementsByClassName('.container') // 集合
const PList = document.querySelectorAll('p') // 集合
```
**property:**修改 dom 結構的變量,不表現在 html 中
```javascript
const pList = document.querySelectorAll('p')
const p1 = pList[0]
// property 形式
p1.style.width = '100px'
console.log(p1.style.width)
p1.className = 'red'
console.log(p1.className)
```
**attribute**:修改 dom 結構的屬性,表現在 html 中
```javascript
const pList = document.querySelectorAll('p')
const p = pList[0]
p.getAttrbute('data-name')
p.setAttribute('data-name','imooc')
p.getAttribute('style')
p.setAttribute('style','font-size:30px')
```
* property:修改對象屬性,不會體現到 html 結構中
* attribute:修改 html 屬性,會修改 html 結構
* 兩者都有可能引起 DOM 重新渲染;優先選擇 property
#### DOM 結構操作
* 新增/插入節點
```javascript
const div1 = document.getElementById('div1')
// 添加新節點
const p1 = document.createElement('p')
p1.innerHTML = 'this is p1'
div1.appendChild(p1) // 添加新創建的元素
// 移動已有節點。移動
const p2 = document.getElementById('p2')
div1.appendChild(p2)
```
* 獲取子元素列表、獲取父元素
```javascript
// 獲取子元素列表
const div1 = document.getElementById('div1')
const child = div1.childNodes
// 獲取父元素
const div1 = document.getElementById('div1')
const parent = div1.parentNode
```
* 刪除節點
```javascript
const div1 = document.getElementById('div1')
const child = div1.childNodes
div1.removeChild(child[0])
```
#### DOM 性能
* DOM 操作非常 “昂貴”,避免頻繁的 DOM 操作
* DOM 查詢作緩存

* 將頻繁操作改為一次性操作

### BOM
* BOM:Browser Object Model
#### navigator、screen
```javascript
// navigator、瀏覽器標識
const ua = navigator.userAgent
const isChrome = ua.indexOf('Chrome')
console.log('isChrome')
// screen 屏幕信息
screen.width
screen.height
```
#### location、history
```javascript
location.href // "https://coding.imooc.com/class/chapter/400.html#Anchor"
location.protocol // 'https'
location.pathname // '/class/chapter/400.html'
location.search // url參數
location.hash // '#Anchor'
// history
history.back() // 后退
history.forward() // 前進
```
### 事件
#### 事件綁定
```javascript
const btn = document.getElementById('btn1')
btn.addEventListener('click',event=>{
console.log('clicked')
event.preventDefault() // 阻止默認行為
})
```
#### 事件冒泡
* 基于 DOM 樹形結構
* 事件會順著觸發元素向上冒泡
* 應用場景:事件代理
```html
<body>
<div id="div1">
<p id="p1">激活</p>
<p id="p2">取消</p>
<p id="p3">取消</p>
<p id="p4">取消</p>
</div>
<div id="div1">
<p id="p5">取消</p>
<p id="p6">取消</p>
</div>
</body>
<script>
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn)
}
const p1 = document.getElementById('p1')
const body = document.body
bindEvent(p1, 'click', (e) => {
// e.stopPropagation() // 阻止冒泡;注釋掉這一行,體會冒泡
alert('激活')
})
bindEvent(body, 'click', (e) => {
alert('取消')
})
</script>
```
#### 事件代理
擴展閱讀:[掘金:js中的事件委托或事件代理詳解](https://juejin.cn/post/6844903589052153869)

### Ajax
```javascript
// 手寫一個簡單的 ajax
function ajax(url) {
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('GET', url, true)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.responseText))
} else {
reject(new Error(xhr))
}
}
}
xhr.send()
})
return p
}
```
#### XMLHttpRequest
```javascript
// get 請求
const xhr = new XMLHttpRequest()
xhr.open('GET', '/data/test.json', true)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
alert(xhr.responseText)
}
}
}
xhr.send(null)
// post 請求
const xhr = new XMLHttpRequest()
xhr.open('POST', '/login', true)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
alert(xhr.responseText)
}
}
}
const postData = {
userName:'zhangsan',
password:'xxx'
}
xhr.send(JSON.stringify(postData))
```
##### xhr.readySate
* 0---未初始化,還沒有調用 send() 方法
* 1---載入,已調用 send() 方法,正在發送請求
* 2---載入完成,sedn() 方法執行完成,已經接收到全部相應內容
* 3---交互,正在解析相應內容
* 4---完成,相應內容解析完成,可以在客戶端調用
##### xhr.status
* http 狀態碼
* 2xx:表示成功處理請求,如 200
* 3xx:需要重定向,瀏覽器直接跳轉,如 301 302 304
* 4xx:客戶端請求錯誤,如 404 403
* 5xx:服務端錯誤
#### 跨域
##### 同源策略
* ajax 請求時,**瀏覽器要求**當前網頁和 server 必須同源(為了保證安全)
* 同源:協議、域名、端口三者必須一致
* 加載圖片 css js 可無視同源策略;img src、link href、script src
##### jsonp
> JSONP是一種發送JSON數據而無需擔心跨域問題的方法。
>
> JSONP不使用該 `XMLHttpRequest` 對象。
>
> JSONP使用 `<script>` 標記代替。
>
> 由于跨域策略,從另一個域請求文件可能會導致問題。
>
> 從另一個域請求外部腳本不會出現此問題。
>
> JSONP利用了這一優勢,并使用腳本標簽而不是 `XMLHttpRequest` 對象來請求文件。
```javascript
// jQuery 實現 jsonp
$.ajax({
url:'http://localhost:8882/x-origin.json',
dataType:'jsonp',
jsonCallback:'callback',
success:function(data){
console.log(data)
}
})
```
##### CORS
* 服務端設置 http header,服務端的設置
```javascript
// 跨域的域名稱,不建議直接寫 "*"
response.setHeader('Access-Control-Allow-Origin', 'https://localhost:8011')
response.setHeader('Access-Control-Allow-Headers', 'X-Requested-With')
response.setHeader('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS' )
// 接受跨域的 coolie
response.setHeader("Access-Control-Allow-Credentials","true")
```
### 存儲
#### cookie
* 本身用于瀏覽器和 server 通訊
* 被 ”借用“ 到本地存儲來
* 可用 document.cookie = '...' 來修改
* 最大 4k
* 默認跟隨 http 請求,發送到服務器
#### localStorage 和 sessionStorage
* HTML5 專門為存儲而設計,最大可存 5M(每個域)
* localStorage 數據會永久儲存,觸發代碼或手動刪除
* sessionStorage 數據只存在于當前會話,瀏覽器關閉則清空
* 一般用 localStorage 會更多一些