js中的常用的节点类型有哪些?
节点类型 | nodeType | nodeName | nodeValue |
---|---|---|---|
Element(元素节点) | 1 | 元素名 | null |
Attr(属性节点) | 2 | 属性名称 | 属性值 |
Text(文本节点) | 3 | #text | 文本内容 |
CDATASection(CDATA节点) | 4 | #cdata-section | 节点的内容 |
EntityReference(实体引用名称节点) | 5 | 实体引用名称 | null |
Entity(实体名称节点) | 6 | 实体名称 | null |
ProcessingInstruction(处理指令节点) | 7 | target | 节点内容 |
Comment(注释节点) | 8 | #comment | 注释内容 |
Document(根节点) | 9 | #document | null |
DocumentType(文档类型节点) | 10 | 文档类型名称 | null |
DocumentFragment(文档片段节点) | 11 | #document片段 | null |
Notation(DTD声明节点) | 12 | 符号名称 | null |
数据绑定
- 第一种方式:利用动态创建元素节点并把它追加到页面中的这种方式是实现数据绑定
for(var i = 0; i <goods.length; i++) {
var item = goods[i];
var oLi = document.createElement('li');
var oImg = document.createElement('img');
var oP1 = document.createElement('p');
var oP2 = document.createElement('p');
var oP3 = document.createElement('p');
var oP4 = document.createElement('p');
oImg.src = item.img;
oP1.innerHTML = item.title;
oP2.innerHTML = "上架时间:" + item.time;
oP3.innerHTML = "价格:" + item.price;
oP4.innerHTML = "热度:" + item.hot;
oLi.appendChild(oImg);
oLi.appendChild(oP1);
oLi.appendChild(oP2);
oLi.appendChild(oP3);
oLi.appendChild(oP4);
goodslist.appendChild(oLi);
}
优势:把需要动态绑定的数据一个一个的追加到页面中,对原来的元素没有任何影响(DOM映射)
弊端:每次创建一个元素都要添加到页面中,每一都会引发一次DOM回流,最终导致计算次数太多,影响性能。
- 第二种方式:字符串拼接的方式,循环需要绑定的数据,然后把需要绑定的数据以字符串的形式拼接到一起,拼接完成后,一次性添加到页面中,减少了DOM回流
let bind_data = function (data) {
let str = ``;
for (let i = 0; i < data.length; i++) {
let { title, price, time, hot, img } = data[i];
str += `
<li data-time="${time}" data-price="${price}" data-hot="${hot}">
<img src="${img}" alt="">
<span>${title}</span>
<span>上架时间:${time}</span>
<span>热度:${hot}</span>
<span>价格:${price}</span>
</li>
`;
}
oList.innerHTML = str;
- 第三种方式,文档碎片动态绑定数据,在所有的节点类型中,只有文档碎片节点DocumentFragment在文档中没有对应的标记,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。(既保证对原有的不影响,也减少了DOM的回流 )
let tempFragment = document.createDocumentFragment();//创建一个文档碎片
for (let i = 0; i < newAry.length; i++) {
tempFragment.appendChild(newAry[i]);//循环遍历,添加到这个碎片中
}
oList.appendChild(tempFragment);//最后一次性添加到页面中
什么是DOM回流?
- 回流(重排 reflow):当页面中的HTML结构发生改变(增加、删除元素、位置发生改变等等),只要结构发生改变,浏览器都需要从新的计算一遍最新的dom结构,从新的对当前的页面进行渲染
- 重绘:某一个元素的部分样式发生改变了(例如:背景颜色),浏览器只需要从新渲染当前元素即可
重排(回流)和重绘读写分离
浏览器渲染页面的时候是按照"先创建DOM数=>在加载CSS=>生成渲染数 RENDER TREE=>把渲染数交给浏览器(CPU)进行绘制",如果后期我们改变了元素的样式(但是没有改变元素的大小和位置),浏览器会把当前元素重新生成渲染数,然后进行重新渲染,这个机制是重绘,但是一旦元素的位置或者大小等发生改变,浏览器就要从DOM数重新计算渲染,这个机制是重排(回流)。无论是重排还是重绘都非常的消耗性能。在我的以前项目中,我特意的注重了这个问题,尽量减少操作DOM引发的回流和重绘问题,常用的解决方案:
1、需要动态的向页面追加元素的时候,基于文档碎片或者先把需要追加的所有元素拼接成字符串最后统一追加到页面中
2、读写分离:把统一修改样式都放到一起执行,新版浏览器都有一个自己检测的机制,如果发现紧挨着的操作也是修改元素的样式,会把所有修改的是存起来,直到遇到非修改样式的操作,会把之前存储的统一执行,引发一次重排和重绘,当然还有一些其他的办法 ,这些是最长注意的,我认为减少DOM回流重绘是非常重要的性能优化手段之一