瀏覽器高性能滑動解決方案
最近一段時間,在項目中實現過瀑布流、懶加載、側邊欄導航等功能。總覺得在處理瀏覽器scroll滑動的時候有點問題,通過計算各個模塊的高度和某些指定模塊的出現時機時,在PC端還好,在移動端容易出現卡頓和抖動的情況。特此整理解決方案。
在停止滑動后執行
如果我們需要在滑動的時候進行某些操作,可以在停止滑動后再延遲進行,這樣就不會一邊滑動一邊執行了。
//滑動停止后延遲wait毫秒后才執行func
function debounce(func, wait) {
// 定時器變量
var timeout;
return function() {
// 每次觸發 scroll handler 時先清除定時器
clearTimeout(timeout);
// 指定 xx ms 后觸發真正想進行的操作 handler
timeout = setTimeout(func, wait);
};
};
// 實際想綁定在 scroll 事件上的處理函數
function realFunc(){
console.log("Success");
}
// 采用了防抖動
window.addEventListener('scroll',debounce(realFunc,500));
// 沒采用防抖動
//window.addEventListener('scroll',realFunc);
還可以更好的封裝一番:
// 防抖動函數
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate & !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
var myEfficientFn = debounce(function() {
// 滾動中的真正的操作
}, 250);
// 綁定監聽
window.addEventListener('scroll', myEfficientFn);
節流,在滑動中間隔執行
如果我們不是在滑動停止后執行,而是在滑動中需要實時計算一些東西,就可以采用 節流 的方式。
節流函數,只允許一個函數在 X 毫秒內執行一次。
// 簡單的節流函數
function throttle(func, wait, mustRun) {
var timeout,
startTime = new Date();
return function() {
var context = this,
args = arguments,
curTime = new Date();
clearTimeout(timeout);
// 如果達到了規定的觸發時間間隔,觸發 handler
if(curTime - startTime >= mustRun){
func.apply(context,args);
startTime = curTime;
// 沒達到觸發間隔,重新設定定時器
}else{
timeout = setTimeout(func, wait);
}
};
};
// 實際想綁定在 scroll 事件上的 handler
function realFunc(){
console.log("Success");
}
// 采用了節流函數
window.addEventListener('scroll',throttle(realFunc,500,1000));
如果在一段時間內 scroll 觸發的間隔一直短于 500ms ,那么能保證事件我們希望調用的 handler 至少在 1000ms 內會觸發一次。
高精度控制
上面的兩種方式都是通過setTimeout來實現的,精度不夠高,如果對瀏覽器兼容性要求不高,或者是移動端web,可以使用原生的 requestAnimationFrame 來實現。
該方法的原理: 在瀏覽器的頁面重繪之前,通知瀏覽器調用一個指定的函數。該方法被調用的頻率為每秒60次 。
所以說用該方法來觸發滾動事件,相當于上面的:
throttle(func, xx, 1000/60) //xx 代表 xx ms內不會重復觸發事件 handler
var ticking = false; // rAF 觸發鎖
function onScroll(){
if(!ticking) {
requestAnimationFrame(realFunc);
ticking = true;
}
}
function realFunc(){
// do something...
console.log("Success");
ticking = false;
}
// 滾動事件監聽
window.addEventListener('scroll', onScroll, false);
這樣瀏覽器就會以16.7ms的頻率觸發事件。
至于移動端,最好還是使用iscroll這樣的模擬事件滑動的庫來解決其延遲問題吧。
來自: http://brizer.github.io/2016/06/11/瀏覽器高性能滑動解決方案/
本文由用戶 vinsonli 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!