介绍
本章介绍 DOM 操作的知识点和题目。包括 DOM 结构,常用 DOM 操作,DOM 性能优化等。DOM 是网页结构的基础,学会 DOM 操作才可以做网页开发。
主要内容
- 从 JS 基础到 JS-Web-API
- DOM 的本质是什么
- DOM 节点操作
- DOM 结构操作
- 如何优化 DOM 操作的性能
JS Web API
背景
JS 基础知识,规定语法(ECMA 262 标准)
JS Web API,网页操作的 API(W3C 标准)
前者是后者的基础,两者结合才能真正实际应用
内容
- DOM:操作网页上的DOM元素,比如文本,图片等
- BOM:操作浏览器上的一些事情,导航,宽高等
- 事件绑定:绑定事件,监听点击之类
- ajax:发送网络请求
- 存储:浏览器暂存数据
DOM的本质
DOM,document object model
DOM的本质是从HTML中解析出来的一棵树,DOM结构就是树结构。
DOM节点操作
DOM节点操作: 获取dom节点: documen.getElementById() document.getElementsByClassName document.getElementsByTagName docuement.querySelectorAll // css选择器 attribute // 对html属性进行修改 property // js操作属性的一种形式 对dom元素的js变量进行修改 const plist = document.querySelectorAll('p') const p1 = plist[0] p1.className // 返回元素的类名 p1.nodeName // 返回节点名称 p1.nodeType // 返回节点类型 一般元素返回的1
attribute
和property
的区别
-
property
:修改对象属性,不会体现到html结构中 (推荐使用:设置js同一变量不一定会重新渲染) -
attribute
:修改html属性,会改变html结构(设置了dom属性就会重新进行dom渲染) -
两者都可能引起dom重新渲染
建议尽量用 property 操作,因为property可能会在JS机制中,避免一些不必要的DOM渲染;但是attribute是修改HTML结构,一定会引起DOM结构的重新渲染,而DOM重新渲染是比较耗费性能的
DOM结构操作
新增/插入节点 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') div2.appendChild(p1) 获取子元素列表,获取父元素 const div1ChildNodes = div1.childNodes cosnole.log(div1.childNodes) const div1ChildNodesP= Array.prototype.slice.call(div1.childNodes).filter(child => {//过滤 if(child.nodeType === 1) {//获得正常DOM节点。而不是text节点 return true } return false }) cosnole.log('div1ChildNodesP',div1ChildNodesP) console.log(p1.parentNode) 删除子元素 div1.removeChild(div1ChildNodesP[0])
如何优化 DOM 操作的性能
DOM 性能 DOM 操作会占用CPU,可能会导致浏览器的重绘和重排,使得运行耗时或者说耗费CPU计算比较多,频繁操作可能会导致卡顿的一些问题
- DOM 查询做缓存
// 不缓存查询
for(let i = 0, i document.getElementsByTagName('p').length, i++) {
// 每次循环,都会计算 length, 频繁进行 DOM 查询
}
// 缓存 DOM 查询结果
const length = document.getElementsByTagName('p').length;
for(let i = 0, i document.getElementsByTagName('p').length, i++) {
// 缓存 length,只进行一次 DOM 查询
}
2.将频繁操作改成一次性操作
const listNode = document.getElementById('list'); // 频繁操作 for(let i = 0, i 10, i++) { const li = document.createElement('li'); li.innerHTML = 'List item' + x; listNode.appendChild(li); } // 频繁操作改为一次性操作 // 创建一个文档片段,此时还没有插入到 DOM 树中 (理解为创建了一个虚拟DOM的teamplate元素) const frag = document.createDocumentFragment(); for(let i = 0, i 10, i++) { const li = document.createElement('li'); li.innerHTML = 'List item' + x; frag.appendChild(li); // 将生成的 li 先插入到 虚拟DOM中 } // 都完成之后,再插入到 DOM 树中 list.appendChild(frag);
下期介绍js的高级用法