本文摘自PHP中文网,作者醉折花枝作酒筹,侵删。
本文给大家介绍Dom节点进行优化的方案。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。DOM操作对性能影响最大是因为它导致了浏览器的重绘和回流,我们都知道页面UI的更改都是通过DOM操作实现的,DOM虽然提供了许多api方便我们操作dom,但DOM操作的代价很高,页面前端代码的性能瓶颈也大多集中在DOM操作上,所以前端性能优化的一个主要的关注点就是DOM操作的优化。
浏览器渲染机制:
浏览器渲染页面
浏览器解析 HTML 文档的源码,然后构造出一个 DOM 树,遇到样式就异步计算。
异步计算好的样式与dom树合成,构建 render 树。
进行布局(layout) render 树。
进行绘制(painting) render 树。
DOM树与render树的区别在于:样式为display:none;的节点会在DOM树中而不在渲染树中。浏览器绘制了之后便开始解析js文件,根据js来确定是否重绘和重排。
回流?重绘
页面更改发生的操作:
- 回流:浏览器引擎发现render树某个节点发生了变化影响了布局,需要倒回去重新渲染,我们称这个回退的过程叫 回流。回流会从这个root frame开始递归往下,依次计算所有的结点几何尺寸和位置。
- 重绘:改变某个元素的背景色、文字颜色、边框颜色等等不影响页面dom布局的操作。
js是单线程的,重绘和重排会阻塞用户的操作以及影响网页的性能
优化:减少回流重绘次数
1、改变dom多个样式,使用class,而非style,减少多次触发回流重绘
举例:改变dom元素宽高
1 2 3 | var dom = document.getElementById( 'box' )
dom.style.width = '300px'
dom.style.height = '300px'
|
优化后:
1 2 3 4 5 | .change {
width: 300px;
height: 300px;
}
document.getElementById( 'p' ).className = 'change'
|
2、列表类型批量修改,脱离文档流再恢复,利用样式为display:none;的节点会在DOM树中而不在渲染树中不会引起重绘回流。
如果要在一个dom集合中,给每个dom子节点加一个class,我们可以遍历给每一个节点都加上class,这样就触发了多次的重绘和回流
1 2 3 4 5 6 7 8 9 10 11 12 13 |
var ul = document.getElementsByTagName( 'ul' )
var lis = document.getElementsByTagName( 'li' )
ul.style.display = 'none'
for ( var i = 0; i < lis.length; i++) {
lis[i].className = 'change' ;
}
ul.style.display = 'block'
|
3、DocumentFragment
虚拟DOM其实就是一个对象,js提供了reateDocumentFragment()方法用于创建一个空的虚拟节点对象,DocumentFragment节点不属于文档树,当需要添加多个dom元素时,如果先将这些元素添加到DocumentFragment中,然后再将DocumentFragment对象添加到渲染树上,会减少页面渲染dom的次数,效率会明显提升。
1 2 3 4 5 6 7 | var frag = document.createDocumentFragment()
for ( var i = 0; i < 10; i++) {
var li = document.createElement( "li" )
li.innerHTML = '我是第' + i + 1 + '个元素'
frag.appendChild(li)
}
ul.appendChild(frag)
|
其它
1、事件委托,利用浏览器事件,冒泡捕获减少页面事件绑定,我们可以指定一个事件处理程序就可以管理某一类型的所有事件。事件函数过多会占用大量内存,而且绑定事件的DOM元素越多会增加访问dom的次数,对页面的交互就绪时间也会有延迟。
1 2 3 4 5 6 7 8 9 | var lis = document.getElementsByTagName( 'li' )
for ( var i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
console.log( this .innerHTML)
}}
var ul = document.getElementsByTagName( 'ul' )ul.onclick = function (event) {
console.log(event.target.innerHTML)};
|
2、在循环中的优化减少操作dom次数
1 2 3 4 5 6 7 | for ( var i = 0; i < 10; i++) {
document.getElementById( 'el' ).innerHTML += '1' }
var str = '' for ( var i = 0; i < 10; i++) {
str += '1' }document.getElementById( 'el' ).innerHTML = str/
|
这样看获取你体验不到缓存节点长度的作用,请看下面的例子
1 2 3 4 5 6 7 8 9 10 11 12 | var ps = document.getElementsByTagName( "p" ), i, p;
for ( i=0; i<ps.length; i++ ){
p = document.createElement( "p" );
document.body.appendChild( "p" );
}造成死循环,每次执行 for 循环都会动态获取ps的长度,而我们每次进入循环都增加了一个DOM(p),ps的长度也+1.
var ps = document.getElementsByTagName( "p" ), i, p,len;
for ( i=0;len=ps.length;i<len; i++ ){
p = document.createElement( "p" );
document.body.appendChild( "p" );
}
|
3、选择器区别
获取元素最常见的有两种方法,getElementsByXXX()和queryselectorAll(),这两种选择器区别是很大的,前者是获取动态集合,后者是获取静态集合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | lis = document.getElementsByTagName( 'li' )
var ul = document.getElementsByTagName( 'ul' )[0]
for ( var i = 0; i < 3; i++) {
console.log(lis.length)
var newLi = document.createElement( 'li' )
ul.appendChild(newLi)}
var lis = document.querySelectorAll( 'li' )
var ul = document.getElementsByTagName( 'ul' )[0]
for ( var i = 0; i < 3; i++) {
console.log(lis.length)
var newLi = document.createElement( 'li' )
ul.appendChild(newLi)}
|
对静态集合的操作不会引起对文档的重新查询,相比于动态集合更加优化。
推荐学习:javascript视频教程
以上就是Dom节点如何进行优化的详细内容,更多文章请关注木庄网络博客!
相关阅读 >>
javascript中src是什么意思
javascript怎么注释多行
如何使用css设计出一个表单页面(附示例)
如何用js求圆的面积
javascript脚本怎么运行
javascript中关于“this”的7个有趣面试题,你能全答对吗?
javascript中怎么退出循环
javascript中声明变量的关键字是什么
javascript中导入js文件的两种方式
javascript主要由哪些部分组成
更多相关阅读请进入《dom》频道 >>
人民邮电出版社
本书对 Vue.js 3 技术细节的分析非常可靠,对于需要深入理解 Vue.js 3 的用户会有很大的帮助。——尤雨溪,Vue.js作者
转载请注明出处:木庄网络博客 » Dom节点如何进行优化