一次性在dom添加多個(gè)節(jié)點(diǎn)會(huì)產(chǎn)生很大的性能問(wèn)題, 一次性加載多個(gè)dom元素的時(shí)候 頁(yè)面會(huì)出現(xiàn)首次加載緩慢或者瀏覽器直接崩潰掉,介紹兩種方法去優(yōu)化
1、分時(shí)函數(shù)
<script type="text/javascript">
function createDom(data) {
const div = document.createElement('div');
div.innerHTML = data;
document.body.appendChild(div);
}
function chunkData (data, num, callback) {
let time;
const start = function() {
for (let i = 0; i < Math.min(num, data.length); i++) {
callback(data.shift());
}
}
time = setInterval(function () {
if(data.length === 0) {
clearInterval(time);
}
start();
} , 300);
}
window.onload = function () {
const data = [];//要加載的數(shù)據(jù)
for(var i = 0; i <= 10000; i++) {
data.push(i);
}
for(let i = 0; i < data.length; i++) { //1.簡(jiǎn)單粗暴的方法
createDom(i);
}
// chunkData(data, 20, createDom);//2.分時(shí)加載
}
</script>
下圖一次性加載多個(gè)dom導(dǎo)致頁(yè)面加載時(shí)間變長(zhǎng)
一次性插入多個(gè)dom頁(yè)面渲染卡頓
采用分時(shí)加載后(使用chunkData方法)
分時(shí)加載
判斷渲染速度是否加快可以判斷當(dāng)發(fā)生 DOMContentLoaded 事件后,就會(huì)生成渲染樹(shù),生成渲染樹(shù)就可以進(jìn)行渲染了,這一過(guò)程更大程度上和硬件有關(guān)系了。
2、虛擬列表
虛擬列表的實(shí)現(xiàn)原理就是只渲染固定屏幕高度的幾條數(shù)據(jù) 每次改變dom元素內(nèi)容 模擬滾動(dòng) 盡量不要去用插入dom并且刪除dom這樣的方式去優(yōu)化 插入刪除dom會(huì)造成瀏覽器的開(kāi)銷 引起瀏覽器回流
-
visibleCount為計(jì)算可視區(qū)域的渲染條數(shù) -
listHeight為列表的總高度 用于撐開(kāi)整個(gè)可視區(qū)域 用于滑動(dòng) -
startIndex和endIndex用于截取渲染數(shù)據(jù)
componentDidMount() {
const { data } = this.state; // 獲取的全部數(shù)據(jù)
this.startIndex = 0
this.listHeight = data.length * this.itemSize;
this.visibleCount = Math.ceil(500 / this.itemSize) // 500是可視區(qū)的高度
this.endIndex = this.visibleCount
this.setState({ visibleData: data.slice(0,this.visibleCount) });
}
滾動(dòng)監(jiān)聽(tīng)事件
this.startOffset的作用是用于定位可視區(qū)域的數(shù)據(jù),因?yàn)榛瑒?dòng)會(huì)將可視區(qū)域的列表向上滑動(dòng) 所以我們要計(jì)算整塊的高度 例如第2個(gè)元素要替換第1個(gè)元素的時(shí)刻 我們將列表向下定位一個(gè)塊的高度 這時(shí)候第一個(gè)元素就正好顯示在屏幕的第一個(gè)位置 否則第一個(gè)元素就會(huì)滑上去了 scrolltop減去this.scrollTop % this.itemSize是因?yàn)槲覀円圃旎瑒?dòng)效果 不能在第一個(gè)元素滑上去的距離小于一整塊高度的時(shí)候去調(diào)整他的top 這樣就不會(huì)有滑動(dòng)效果了
.wrapper {
margin-top: 100px;
border: 1px solid red;
height: 500px;
overflow: scroll;
position: relative;
-webkit-overflow-scrolling: touch;
}
.item {
height: 50px;
border: 1px solid darkcyan;
}
.phantom {
position: absolute;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
.list {
left: 0;
right: 0;
top: 0;
position: absolute;
text-align: center;
}
onScrollList = (val) => {
const { data } = this.state;
this.startIndex = Math.floor(this.refs.lala.scrollTop / this.itemSize);
this.endIndex = this.startIndex + this.visibleCount;
this.scrollTop = this.refs.lala.scrollTop;
this.startOffset = this.scrollTop - (this.scrollTop % this.itemSize);
this.setState({ visibleData: data.slice(this.startIndex, Math.min(this.endIndex, data.length)) });
}
render () {
const { visibleData } = this.state;
return (
<div className='wrapper' ref={'lala'} onScroll={this.onScrollList}>
<div className='phantom' style={{ height: this.listHeight + 'px' }}></div>
<div className='list' style={{ top: this.startOffset + 'px' }}>
{
visibleData.map((item) => <div className='item'>{item}</div>)
}
</div>
</div>
)
}

優(yōu)化前頁(yè)面卡住空白

渲染后性能綠油油????