面试题
1、DOM是哪些数据结构
DOM树
2、DOM操作的常用API
3、attr和property的区别
4、一次性插入多个DOM节点,考虑性能
DOM本质
DOM树
DOM节点操作
- 获取DOM节点
const div1 = document.getElementById("div1")//元素
const divList = document.getElementsByTagName("div")//集合
const containerList = document.getElementsByClassName(".container")//集合
const pList = document.querySelectorAll('p')//集合
- DOM节点的attribute
const pList = document.querySelectorAll("p")
const p = pList[0]
p.getAttribute('data-name')
p.setAttribute('data-name','test')
p.getAttribute('style')
p.setAttribute('style','font-size:30px;')
- DOM节点的property
const pList =document.querySelectorAll('p')
const p = pList[0]
console.log(p.style.width)//获取样式
p.style.width='100px'//修改样式
console.log(p.className)//获取class
p.className = 'p1'//修改class
//获取nodeName和nodeType
console.log(p.nodeName)
console.log(p.nodeType)
property和attribute
- property:修改对象属性,不会体现到html结构中
- attribute:修改html属性,会改变html结构
- 两者都有可能会引起DOM重新渲染
- property是DOM中的属性,是JavaScript⾥的对象;
- attribute是HTML标签上的特性,它的值只能够是字符串;
- 简单理解,Attribute就是dom节点⾃带的属性,例如html中常⽤的id、class、title、align等。
- ⽽Property是这个DOM元素作为对象,其附加的内容,例如childNodes、firstChild等。
DOM结构操作
<body>
<div id="div1">
<p id="p1">一段文字</p>
<p>一段文字</p>
<p>一段文字</p>
</div>
<div id="div2">
<span>ces</span>
</div>
</body>
- 新增/插入节点
const div1 = document.getElementById("div1")
const div2 = document.getElementById("div2")
新增节点
const newP = document.createElemnt('p')
newP.innerHTML = 'this is newP'
//插入节点
const p1 = document.getElementById('p1')
div2.appendChild(p1)
- 获取子元素列表,获取父元素
//获取父元素
console.log(p1.parentNode)
//获取子元素列表
console.log(div1.childNodes)
const div1ChidNodesP = Array.prototype.slice.call(div1.childNodes).filter(child=>child.nodeType===1)
- 删除子节点
const div1 = document.getElementById('div1')
const child = div1.childNodes
div1.removeChild(child[0])
DOM性能
- 1、DOM查询做缓存
不要频繁的去查询DOM,把查询到的内容保存在变量中,后面直接通过变量来操作就好。
//未优化前,要频繁的查询DOM
for (var i = 0; i < document.querySelectorAll("li").length; i++) {....... }
//优化后,只需要查询一次DOM
var n = document.querySelectorAll("li").length;
for (var i = 0; i < n; i++) {......}
//优化后与优化前耗时对比未优化前耗时优化后耗时206.722900390625 ms154.436767578125 ms<script>
window.onload = function () {
//优化前代码
console.time("时间记录");//测试执行时间代码
for (var i = 0; i < document.querySelectorAll("li").length; i++) {
console.log(i);
}
- 2、将频繁操作改为一次一次性操作
这里面要理解一个概念DOM文档片段(虚拟节点对象)文档片段的作用是充当其它要被添加到文档的节点的仓库 。他自己永远不会被添加到文档树中,但是他能包含和操作节点。可以通过document.createDocumentFragment()方法来创建文档片段。
const listdom = document.getElementById("list");
//创建一个文档片段,些时还没有插入到DOM中,存在内存中
const frag = document.createDocumentFragment();
//执行行入操作
for (let x = 0; x < 10000; x++) {
const li = document.createComment("li");
//将DOM先放到文档片段中,这样不会频繁操作DOM
frag.appendChild(li);
}
//最后一次性将10000个li插入到DOM树中
listdom.appendChild(frag);
console.timeEnd("优化后");
- 3、将频繁操作改为一次一次性操作
//优化前样式代码
oLi.style.width = "100px";
oLi.style.height = "20px";
oLi.style.background = "pink";
//方法一:用cssText一次性处理
oLi.style.cssText = "width:100px;height:20px;background:pink";
//方法二:用className一次性处理
.item{width:100px;height:20px;background-color:pink;} /*定义类样式*/
oLi.className='item' //js添加类样式
//三种情况下,消耗时间对比
//方法一:优化前方法二:cssText处理后方法三:className处理后370.9970703125 ms243.667236328125 ms147.678955078125 ms
- 4、操作DOM前,先把DOM节点删除或隐藏
如果要对一个元素进行多次DOM操作,可以先将其隐藏,操作完成后再显示。这样只在隐藏和显示时触发2次重排,而不会是在每次进行操作时都出发一次重排。因为display:none时的元素不在渲染树中,因此对隐藏的元素操作不会引发其他元素的重排。