* 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 查询作缓存
![image-20210306115222530](https://image.mdashen.com/pic/image-20210306115222530.png)
* 将频繁操作改为一次性操作
![image-20210306115307526](https://image.mdashen.com/pic/image-20210306115307526.png)
### 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)
![image-20210306191353215](https://image.mdashen.com/pic/image-20210306191353215.png)
### 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 会更多一些