0%

前端性能优化-DOM性能优化

前言

前端需要频繁操作 DOM,为了提高网站性能,需要针对 DOM 操作进行相应优化。

使用DOM的引用

比如:我们需要对一组 li 标签进行遍历操作,我们可以用一个变量 length 把这组 li 标签的长度保存下来,然后基于length 进行遍历。

使用事件代理批量处理事件

比如:给一系列子元素 li 添加绑定事件,可以通过事件代理来进行优化。

1
2
3
4
5
6
7
// container:父元素
container.addEventListener('click', function (e) {
target = e.target || e.srcElement;
if (target.tagName.toLowerCase() == 'li') {
// 触发click后要做的事情
}
}, false)

使用文档碎片

DocumentFragments 是DOM节点。它们不是主DOM树的一部分。通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。在DOM树中,文档片段被其所有的子元素所代替。

因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能。

这个方法真是处理批量标签的一大利器,使用它可以节省下很多时间,提高 DOM 性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let container = document.getElementById('container');
let wrapper = document.createDocumentFragment; // 使用文档碎片
for (let i = 0; i < data.length; i++) {
let li = document.createElement('li');
li.innerText = data[i];
}
wrapper.appendChild(li);
container.appendChild(wrapper);
container.addEventListener('click', function (e) {
target = e.target || e.srcElement;
if (target.tagName.toLowerCase() == 'li') {
// 触发click后要做的事情
}
}, false)

使用innerHTML一次性添加DOM节点

1
2
3
4
5
6
7
8
var container = document.getElementById('container');
var sHtml = '';
var len = data.length;
var i, li;
for (i = 0; i < len; i++) {
sHtml += '<li>' + data[i] + '</li>';
}
container.innerHTMl = sHtml; // 最后一次性添加到页面中,只出发浏览器一次重排

通过className来批量修改元素样式

经常有这样的场景,我们需要在js中批量的修改元素的样式,比如

1
2
3
4
ele.style.width = 100 + 'px';
ele.style.height = 100 + 'px';
ele.style.backgrounfColor = 'red';
ele.style.border = 'solid 1px green';

以上代码会多次出发浏览器重绘和重排,一种好的方式是将需要修改的样式在样式文件中先写好,通过给元素赋值className的形式批量修改样式

1
2
3
4
5
6
.active{
width: 100px;
height: 100px;
backgroung-color: red;
border: solid 1px green;
}

给元素赋值className

1
ele.className += ' active'; // 注意前面的空格

如何渲染几万条数据并不卡住界面

可以通过 requestAnimationFrame 动画,动态渲染数据。

与setTimeout相比,requestAnimationFrame最大的优势是由系统来决定回调函数的执行时机。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>如何渲染几万条数据并不卡住界面</title>
</head>
<body>
<ul>
控件
</ul>
<script>
// 异步任务 避免阻塞
setTimeout(() => {
// 插入十万条数据
const total = 100000
// 一次插入 20 条,如果觉得性能不好就减少
const once = 20
// 渲染数据总共需要几次
const loopCount = total / once
// 循环渲染次数
let countOfRender = 0
let ul = document.querySelector('ul')
function add() {
// 使用文档碎片 优化性能,插入不会造成回流
const fragment = document.createDocumentFragment()
for (let i = 0; i < once; i++) {
const li = document.createElement('li')
li.innerText = Math.floor(Math.random() * total)
fragment.appendChild(li)
}
ul.appendChild(fragment)
countOfRender += 1
loop()
}
function loop() {
// 循环条件判断
if (countOfRender < loopCount) {
window.requestAnimationFrame(add)
}
}
loop()
}, 0)
</script>
</body>
</html>

参考

-------------本文结束感谢您的阅读-------------