文章目录
一、DOM
1.1 property与attribute的区别
前者修改js变量的值(可修改对象属性),但不会作用到html结构中;
后者直接修改html标签属性,会改变html结构;
两者都可能引起DOM渲染
property:
var p1 = document.querySelectorAll('p')[0]
p1.style.width = '100px'
attribute:
var p1 = document.querySelectorAll('p')[0]
p1.setAttribute('data-name', 'imooc')
1.2 节点操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>dom 演示</title>
<style>
.container {
border: 1px solid #ccc;
}
.red {
color: red;
}
</style>
</head>
<body>
<div id="div1" class="container">
<p id="p1">一段文字 1</p>
<p>一段文字 2</p>
<p>一段文字 3</p>
</div>
<div id="div2">
<img src="https://img3.mukewang.com/5a9fc8070001a82402060220-100-100.jpg"/>
</div>
<ul id="list">
</ul>
<script src="./dom-3.js"></script>
</body>
</html>
const div1 = document.getElementById('div1')
const div2 = document.getElementById('div2')
1.新建节点:document.createElement(tagname)
const newP = document.createElement('p')
newP .innerHTML = 'this is newP'
2.插入节点:父元素.appendChild(新标签)
div1.appendChild(newP)
3.移动节点:其他父元素.appendChild(其他父元素或其子元素)
const p1 = document.getElementById('p1')
div2.appendChild(p1)
4.获取父元素:子元素.parentNode
5.获取子元素列表:父元素.childNodes(包含子元素的纯文本)
解决方案:const div1ChildNodesP = Array.prototype.slice.call(div1.childNodes).filter(child => { if (child.nodeType === 1) { return true } return false })
6.删除子元素
div1.removeChild( div1ChildNodesP[0] )
1.3 DOM性能优化
避免频繁的dom操作:
- for循环操作元素列表时,用js变量length存储document.getElementByClassName().length的值
for(let i=0;i<document.getElementByClassName().length;i++){
...
}
改为:
var length = document.getElementByClassName().length
for(let i=0;i<length ;i++){
...
}
- 对于for循环内部频繁的dom操作(比如一次性插入多个节点),还可以先建立一个文档片段,最后统一插到DOM结构中
const list = document.getElementById('list')
for (let i = 0; i < 20; i++) {
const li = document.createElement('li')
li.innerHTML = `List item ${i}`
list.appendChild(li) //频繁dom操作
}
console.log(list)
改为
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操作
}
// 都完成之后,再统一插入到 DOM 结构中
list.appendChild(frag)
console.log(list)
二、事件
2.1 编写一个通用的事件监听函数
事件绑定:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>事件 演示</title>
<style>
div {
border: 1px solid #ccc;
margin: 10px 0;
padding: 0 10px;
}
</style>
</head>
<body>
<button id="btn1">一个按钮</button>
<div id="div1">
<p id="p1">激活</p>
<p id="p2">取消</p>
<p id="p3">取消</p>
<p id="p4">取消</p>
</div>
<div id="div2">
<p id="p5">取消</p>
<p id="p6">取消</p>
</div>
<div id="div3">
<a href="#">a1</a><br>
<a href="#">a2</a><br>
<a href="#">a3</a><br>
<a href="#">a4</a><br>
<button>加载更多...</button>
</div>
<script src="./event.js"></script>
</body>
</html>
// 普通绑定的事件监听函数
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn)
}
// 普通绑定
const btn1 = document.getElementById('btn1')
bindEvent(btn1, 'click', function (event) {
// console.log(event.target) // 获取触发的元素
event.preventDefault() // 阻止默认行为
alert(this.innerHTML)
})
// 包含代理绑定和普通绑定的通用事件监听函数
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 div3 = document.getElementById('div3')
bindEvent(div3, 'click', 'a', function (event) {
event.preventDefault()
alert(this.innerHTML)
})
2.2 描述事件冒泡的流程
事件冒泡:基于DOM树形结构,事件会顺着触发元素依次往靠近根节点方向冒泡。
const body = document.body
bindEvent(body, 'click', event => {
console.log('body clicked')
// console.log(event.target)
})
// 普通绑定
const div2 = document.getElementById('div2')
bindEvent(div2, 'click', event => {
event.preventDefault() // 阻止默认行为
event.stopPropagation()// 阻止body冒泡
console.log('div2 clicked')
console.log(event.target)// 获取触发的元素
})
const p5 = document.getElementById('p5')
bindEvent(p5, 'click', event => {
event.stopPropagation() // 阻止div2和body冒泡
console.log('p5 clicked')
})
练习题: 无限下拉的图片列表,如何监听每个图片的点击
提示:事件代理;用event.target获取触发元素;用matches判断是否为触发元素。
三、ajax
3.1 ajax实现流程
- post请求
const xhr = new XMLHttpRequest()
xhr.open('POST',url,true)
xhr.onreadystatechange = function(){
if (xhr.readyState===4 && xhr.status === 200)
//JSON.parse(xhr.responseText)
console.log(xhr.responseText)
else alert('error')
}
postData = {}
xhr.send(JSON.stringify(postData))
- get请求(结合promise)
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 if (xhr.status === 404 || xhr.status === 500) {
reject(new Error('404 not found'))
}
}
}
xhr.send(null)
})
return p
}
const url = '/data/test.json'
ajax(url)
.then(res => console.log(res))
.catch(err => console.error(err))
3.2 xhr.readyState 和 xhr.status
- xhr.readyState
0: 未初始化,还未调用open方法
1:(载入)已调用send方法,正在发送请求
2:(载入完成)已接收到全部响应内容
3:(交互)正在解析响应内容
4:(完成)响应内容解析完成,可在客户端调用
- xhr.status
1xx:服务器收到请求
2xx:成功处理请求,200
3xx:重定向,浏览器直接跳转,301永久重定向,302临时重定向,304资源未改变
4xx:客户端请求错误,404请求路由未找到,403权限不够
5xx:服务端错误
3.3 跨域的实现方式
-
跨域与同源
ajax请求时,浏览器要求客户端和服务端必须同源(协议、域名、端口三者必须一致),所有的跨域都必须经过server端允许和配合 -
图片标签src属性、link标签的href属性(css)、script标签的src属性(js)可无视同源策略
-
jsonp
jsonp的实现原理:script标签可绕过跨域限制,获得跨域数据;服务器可任意拼接数据返回
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>jsonp 演示</title>
</head>
<body>
<p>一段文字 1</p>
<script>
window.abc = function (data) {
console.log(data)
}
</script>
<script src="http://localhost:8002/jsonp.js?username=xxx&callback=abc"></script>
</body>
</html>
jsonp.js
abc(
{ name: 'xxx' }
)
jQuery实现jsonp
$.ajax({
url:"http://localhost:8002/jsonp.js?username=xxx&callback=abc",
dataType:'jsonp',
jsonpCallback:'abc',
success:function (data){
console.log(data)
}
})