[TOC]
一、DOM
DOM,即文档对象模型(Document Object Model),它是从 HTML 解析出来的一个树结构
1、DOM 节点操作
1.1 获取 DOM 节点
const div1 = document.getElementById('div1') // 元素
console.log('div1', div1)
const divList = document.getElementsByTagName('div') // 集合
console.log('divList.length', divList.length)
console.log('divList[1]', divList[1])
const containerList = document.getElementsByClassName('container') // 集合
console.log('containerList.length', containerList.length)
console.log('containerList[1]', containerList[1])
const pList = document.querySelectorAll('p') // 集合
console.log('pList', pList)
1.2 DOM 节点的 property
property 是 DOM 中的属性,是一个 js 对象。我们可以用对象形式修改/获取 DOM 节点的属性。它修改对象属性,不会体现到 html 结构中
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)
console.log(p1.nodeName)
console.log(p1.nodeType) // 1
1.3 DOM 节点的 attribute
attribute 是 html 标签的某个特性,如:id、value等,值只能是字符串,可通过 getAttribute
和 setAttribute
对其进行获取或修改,它修改 html 属性,会改变 html 结构
// attribute
p1.setAttribute('data-name', 'hello')
console.log(p1.getAttribute('data-name'))
p1.setAttribute('style', 'font-size: 50px;')
console.log(p1.getAttribute('style'))
2、DOM 结构操作
<div id="div1" class="container">
<p id="p1">一段文字 1</p>
<p>一段文字 2</p>
<p>一段文字 3</p>
</div>
<div id="div2">
<img src="url"/>
</div>
<ul id="list"></ul>
2.1 新增/插入/移动节点
const div1 = document.getElementById('div1')
const div2 = document.getElementById('div2')
// 新建节点
const newP = document.createElement('p')
newP.innerHTML = 'this is newP'
// 插入节点
div1.appendChild(newP)
// 移动节点
const p1 = document.getElementById('p1') // 对现有节点执行 appendChild 会移动节点
div2.appendChild(p1)
2.2 获取/删除子元素、获取父元素
// 获取父元素
console.log(p1.parentNode)
// 获取子元素列表
const div1ChildNodes = div1.childNodes
console.log(div1.childNodes)
const div1ChildNodesP = [...div1.childNodes].filter(child => {
if (child.nodeType === 1) {
return true
}
return false
})
console.log('div1ChildNodesP', div1ChildNodesP)
// 删除子元素
div1.removeChild(div1ChildNodesP[0])
3、DOM 性能优化
3.1 DOM 查询做缓存
// 不缓存 DOM 查询结果
for (let i = 0; i < document.getElementsByTagName('p').length; i += 1) {
// 每次循环,都会计算 length,频繁进行 DOM 查询
}
// 缓存 DOM 查询结果
const len = document.getElementsByTagName('p').length
for (let i = 0; i < len; i += 1) {
// 缓存 length, 只进行一次 DOM 查询
}
3.2 频繁操作改为一次性操作
使用 createDocumentFragment
创建文档片段进行优化
const list = document.getElementById('list')
// 创建一个文档片段,此时还没有插入到 DOM 结构中
const frag = document.createDocumentFragment()
for (let i = 0; i < 20; i++) {
const li = document.createElement('li')
li.innerHTML = `List item ${i}`
// 先插入文档片段中
frag.appendChild(li)
}
// 都完成之后,再统一插入到 DOM 结构中
list.appendChild(frag)
console.log(list)
二、BOM
BOM,即浏览器对象模型(Browser Object Model),常见的 window 对象中的 navigator、screen、location、history等
// navigator
const ua = navigator.userAgent // 当前浏览器信息
const isChrome = ua.indexOf('Chrome')
console.log(isChrome)
// screen
console.log(screen.width)
console.log(screen.height)
// location
console.log(location.href) // 整个网址
console.log(location.protocol) // 协议 http: / https:
console.log(location.pathname) // 路径
console.log(location.host) // 域名
console.log(location.search) // 查询参数
console.log(location.hash) // 哈希(#号后面)
// history
history.back() // 后退
history.forward() // 前进
三、事件
1、事件绑定
1.1 基本绑定语法
const btn = document.getElementById("btn")
btn.addEventListener('click', event => {
console.log('clicked')
})
1.2 通用绑定函数
基础版:
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn)
}
const btn1 = document.getElementById('btn1')
bindEvent(btn1, 'click', function (event) {
event.preventDefault() // 阻止默认行为
alert('clicked')
})
进阶版(支持事件代理逻辑):
function bindEvent(elem, type, selector, fn) {
if (fn == null) {
fn = selector
selector = null
}
elem.addEventListener(type, event => {
const target = event.target
if (selector) {
// 代理绑定
if (target.matches(selector)) {
fn.call(target, event)
}
} else {
// 普通绑定
fn.call(target, event)
}
})
}
// 普通绑定
const btn1 = document.getElementById('btn1')
bindEvent(btn1, 'click', function (event) {
// console.log(event.target) // 获取触发的元素
event.preventDefault() // 阻止默认行为
alert(this.innerHTML)
})
// 代理绑定
const div3 = document.getElementById('div3')
bindEvent(div3, 'click', 'a', function (event) {
event.preventDefault()
alert(this.innerHTML)
})
2、事件冒泡
如果没有调用 stopPropagation
,则点击 p1 会逐级 p1 -> div1 -> body 往上冒泡,效果就像依次点击了p1、div1、body,逐个触发点击事件
3、事件代理
事件代理(事件委托)即把子元素的事件绑定到父元素上,原理是基于事件冒泡
四、Ajax
1、XMLHttpRequest
1.1 基本使用
// get 请求
const xhr = new XMLHttpRequest()
xhr.open('GET', '/test.json', true)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
alert(xhr.responseText)
} else {
alert('其他情况')
}
}
}
xhr.send(null)
// post 请求
xhr.open('POST', '/login', true)
xhr.onreadystatechange = function () {
// ...
}
const postData = {
userName: 'zhangsan',
password: '123'
}
xhr.send(JSON.stringify(postData))
1.2 简易 ajax 手写
function ajax(url) {
return 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 if (xhr.status === 404) {
reject(new Error('404 Not Found'))
}
}
}
xhr.send(null)
})
}
ajax('./test.json')
.then(res => console.log(res))
.catch(err => console.error(err))
1.3 readyState
- 0 -(未初始化)还没有调用 send() 方法
- 1 -(载入)已调用 send() 方法,正在发送请求
- 2 -(载入完成)send() 方法执行完成,已经接收到全部响应内容
- 3 -(交互)正在解析响应内容
- 4 -(完成)响应内容解析完成,可以在客户端调用
1.4 status(状态码)
- 2xx - 表示成功处理请求,如:200
- 3xx - 需要重定向,浏览器直接跳转
- 301 - 永久重定向
- 302 - 临时重定向
- 304 - 资源未改变,浏览器会使用缓存
- 4xx - 客户端请求错误
- 403 - 客户端无权限
- 404 - 请求地址错误
- 5xx - 服务器端错误
2、跨域
跨域产生的原因是由于浏览器的同源策略
- 同源策略:ajax 请求时,浏览器要求当前网页和 server 必须同源
- 同源:协议、域名、端口,三者必须都一致
但加载图片、CSS、JS 可无视同源策略
<img src="跨域的图片地址" />
<link href="跨域的css地址" />
<script src="跨域的js地址"></script>
利用特性,可有以下这些使用场景:
- 可用于统计打点,可使用第三方统计服务
- 和