1. 什么是DOM
- 用于操作XML和HTML文档的应用程序
- DOM节点(ul,li)
- DOM树(DOM节点的整体)
- DOM API
- getElementById
- childNodes
- appendChild
- innerHTML
2. Dom与JavaScript
1)概念
- 浏览器会把dom与js独立实现
- 像两个独立的小岛
- js操作 dom
- 从一个岛到另一个岛
- dom的性能
- 岛与岛之间的桥,每次通过收取“过桥费”
- 尽量减少过桥的次数
- innerHTML与dom方法对比
2)举例
以下代码运行时间为600ms左右
window.onload=function(){
var oDiv=document.getElementById('div1');
console.time('hello');
for(var i=0;i<5000;i++){
oDiv.innerHTML+='a';
}
console.timeEnd('hello');
}
以下代码运行时间为1ms左右,定义一个变量str
window.onload=function(){
var oDiv=document.getElementById('div1');
var str='';
console.time('hello');
for(var i=0;i<5000;i++){
str+='a';
}
oDiv.innerHTML=str;
console.timeEnd('hello');
}
3)关于innerHTML与dom方法对比
以下使用DOM方法操作,时间为350ms左右
window.onload=function(){
var oUl=document.getElementById('ul1');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi=document.createElement('li');
oUl.appendChild(oLi);
}
console.timeEnd('hello');
}
以下使用innerHTML方法操作,时间为290ms左右
window.onload=function(){
var oUl=document.getElementById('ul1');
var str='';
console.time('hello');
for(var i=0;i<5000;i++){
str += '<li></li>';
}
oUl.innerHTML=str;
console.timeEnd('hello');
}
注意:以上是在火狐中,但是在Chrome浏览器中,上面为10ms,下面为44ms
chrome:dom方法要比innerHTML性能要好。
3. 减少DOM操作
- 节点克隆
- cloneNode
- 访问元素集合
- 尽量用局部变量
- 元素节点
- 尽量用只获取元素的节点方法
- 选择器API
- 利用querySelector,querySelectorAll
1)节点克隆
运行时间440ms左右
window.onload=function(){
var oUl=document.getElementById('ul1');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi=document.createElement('li');
oLi.innerHTML='li';
oUl.appendChild(oLi);
}
console.timeEnd('hello');
}
使用节点克隆,运行时间为360ms
window.onload=function(){
var oUl=document.getElementById('ul1');
console.time('hello');
var oLi=document.createElement('li');
oLi.innerHTML='li';
for(var i=0;i<5000;i++){
var newLi=oLi.cloneNode(true);
oUl.appendChild(newLi);
}
console.timeEnd('hello');
}
2)访问元素集合
460ms
window.onload=function(){
var oUl=document.getElementById('ul1');
var aLi=oUl.getElementsByTagName('li');
for(var i=0;i<5000;i++){
var oLi=document.createElement('li');
oUl.appendChild(oLi);
}
console.time('hello');
for(var i=0;i<aLi.length;i++){
aLi[i].innerHTML='li';
}
console.timeEnd('hello');
}
用局部变量,450ms
window.onload=function(){
var oUl=document.getElementById('ul1');
var aLi=oUl.getElementsByTagName('li');
for(var i=0;i<5000;i++){
var oLi=document.createElement('li');
oUl.appendChild(oLi);
}
console.time('hello');
var len=aLi.length;
for(var i=0;i<len;i++){
aLi[i].innerHTML='li';
}
console.timeEnd('hello');
}
在其他方面的应用
var oDiv=document.getElementById('div');
var oUl=document.getElementById('ul');
换成下面这种方式性能会提高很多
var doc=document;
var oDiv=doc.getElementById('div');
var oUl=doc.getElementById('ul');
3)元素节点(尽量用只获取元素的节点方法)
childNodes ->元素节点、文本节点
children ->元素节点
firstChils
firstElementChild
4)选择器API
var oUl=document.getElementById('ul1');
var aLi=oUl.getElementsByTagName('li');
可以这样写
var aLi=document.querySelectorAll('#UL1 li');
4. Dom与浏览器
- 重排:改变页面的内容
- 重绘:浏览器显示内容
- 添加顺序
- 尽量在appendChild前添加操作
- 合并dom操作
- 利用cssText
- 缓存布局信息
- 文档碎片
- createDocumentFragment()
- Dom与事件
- 事件委托
- Dom与前端模板
- 能更好的对逻辑和视图分离,MVC架构的基础
1)添加顺序( 尽量在appendChild前添加操作)
750ms
window.onload=function(){
var oUl=document.getElementById('ul1');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi=document.createElement('li');
oUl.appendChild(oLi);
oLi.innerHTML='li';
}
console.timeEnd('hello');
}
450ms。不会进行重排重绘的过程。
window.onload=function(){
var oUl=document.getElementById('ul1');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi=document.createElement('li');
oLi.innerHTML='li';//调换顺序
oUl.appendChild(oLi);
}
console.timeEnd('hello');
}
2)合并dom操作(利用cssText)
500ms
window.onload=function(){
var oUl=document.getElementById('ul1');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi=document.createElement('li');
oLi.style.width='100px';
oLi.style.height='100px';
oLi.style.background='red';
oUl.appendChild(oLi);
}
console.timeEnd('hello');
}
490ms
window.onload=function(){
var oUl=document.getElementById('ul1');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi=document.createElement('li');
oLi.style.cssText='width:100px;height:100px;background:red;';
oUl.appendChild(oLi);
}
console.timeEnd('hello');
}
3)缓存布局信息
//div1是一个红色的100px的正方块
window.onload=function(){
var oDiv=document.getElementById('div1');
setInterval(function(){
oDiv.style.left=oDiv.offsetLeft+1+'px';
oDiv.style.top=oDiv.offsetTop+1+'px';
},30);
};
如何利用缓存布局信息
//div1是一个红色的100px的正方块
window.onload=function(){
var oDiv=document.getElementById('div1');
var L=oDiv.offsetLeft;
var T=oDiv.offsetTop;
setInterval(function(){
L++;T++;
oDiv.style.left=L+'px';
oDiv.style.top=T+'px';
},30);
};
4)文档碎片(createDocumentFragment())
360ms
window.onload=function(){
var oUl=document.getElementById('ul1');
console.time('hello');
for(var i=0;i<5000;i++){
var oLi=document.createElement('li');
oUl.appendChild(oLi);
}
console.timeEnd('hello');
}
300ms
window.onload=function(){
var oUl=document.getElementById('ul1');
var oFrag=document.createDocumentFragment();
console.time('hello');
for(var i=0;i<5000;i++){
var oLi=document.createElement('li');
oFrag.appendChild(oLi);
}
oUl.appendChild(oFrag);
console.timeEnd('hello');
}