1. 業務邏輯描述
2. 優化后的性能提升對比
相當明顯
3. 常規處理邏輯
把左側菜單的一項成為分類(category),
把右側每一項稱為項(item)。
- DOM更新后,獲取整個content的高度(包裹所有item的盒子的高度);
- 獲取每個category在content上的高度,從而獲取跳轉y值區間數組
jumpArr
; - 在content上監聽滑動事件,判斷當前
y
值在jumpArr
中的位置,更新左側category樣式。
這種方法處理的問題(性能上的)
每次觸發scroll事件后都會遍歷數組jumpArr
來判斷此刻左側導航該有的樣式。scroll事件的觸發是相當密集的,也就是jumpArr
的遍歷也是相當密集。對性能有很大的影響。特別是當應用越來越大時、設備比較老舊時。
4. 我的優化思路
- 標題2中的1、2步保持不變,通過相同的方法獲得
jumpArr
; - 上面步驟3采用的是實時遍歷,現在拋棄這種做法。而是,生產一個跳轉函數,可以使用
if...else
也可以使用switch...case
,這里選用后者,因為性能更加出眾。
注:生成的jumpFunc
是字符串,需要使用eval()
來進行函數轉換。
5. 代碼示例(vue)
- 計算獲取
jumpArr
getGoodsHeight() {
//這兩項是用來獲取content總高的
const specials = document.querySelector(".specials");
const itemList = document.querySelectorAll(".group-item");
//預賽了
let heightList = [];
heightList.push(specials.offsetHeight);
itemList.forEach((element, index) => {
const eleHeight = element.offsetHeight;
const preheight = heightList[index];
heightList.push(preheight + eleHeight);
});
this.heightList = heightList;
}
- 根據
jumpArr
得出用於邏輯處理的跳轉函數jumpFunc
getJumpFunc() {
//這樣的寫法有助於性能,使用判斷而不是用循環
let i = 0;
let func = `(function () { return function (y, context) {`;
const length = this.heightList.length;
while (i < length) {
const current = this.heightList[i - 1] || 0;
const next = this.heightList[i];
const lastIndex = length - 1;
let partition = "";
switch (i) {
case 0:
partition = `if(y > 0 && y< ${next}) { context.addNavStyle(${i}) }`;
break;
case lastIndex:
partition = `else { context.addNavStyle(${i}) }};})();`;
break;
default:
partition = `else if (y > ${current} && y <${next}) { context.addNavStyle(${i}) }`;
break;
}
func += partition;
i++;
}
return eval(func);
},
- 項目地址