成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

優(yōu)化移動端window.onscroll的執(zhí)行頻率方案

Simon / 1023人閱讀

摘要:腦洞爆炸的背景最近開發(fā)項目動效開發(fā)越來越多部分動效需要在頁面滑動的時候執(zhí)行一定的效果但是發(fā)現(xiàn)在移動端很多時候頁面滑動的速度快的時候,動效呈現(xiàn)的不穩(wěn)定性越明顯,會不流暢雖然使用的過渡可以從視覺層面解決這個問題,但是并不能根治,于是乎想到了一個

腦洞爆炸的背景

最近開發(fā)項目動效開發(fā)越來越多 ;
部分動效需要在頁面滑動的時候執(zhí)行一定的效果;
但是發(fā)現(xiàn)在移動端 很多時候頁面滑動的速度快的時候 , 動效呈現(xiàn)的不穩(wěn)定性越明顯 , 會不流暢; 雖然使用css3的過渡可以從視覺層面解決這個問題 , 但是并不能根治, 于是乎想到了一個方案。。。

requestAnimationFrame(RAF)

h5新增的用于刷幀的api , 大家可以網(wǎng)上找到很多相關(guān)教程 , 用法及其簡單 , 跟使用setTimeOut一樣; 此api的初衷本人理解為用于更好的執(zhí)行動畫 , 而找到的一句話 “執(zhí)行渲染下一幀之前的動作”可能更好的幫助你理解這個api;

方案

而之前說的移動端動畫不流暢的原因是因為快速滑動的時候 , 兩次出發(fā)scroll之間的“間距”越來越大,而導(dǎo)致需要根據(jù)滑動計算的精度越來越不準 , 我們當(dāng)然希望每滑動1px執(zhí)行一次scroll是最完美的啦~(雖然基本不可能)

于是乎 , 想到了一個方案?!

可以在window.scroll開始的時候開啟RAF,在window.scroll結(jié)束的時候關(guān)閉RAF , 所有需要執(zhí)行在scroll中的函數(shù)搬到RAF中執(zhí)行就好了

事實上實驗結(jié)果是成功的

每次window.scroll的時候在頁面插入一次scroll字樣 , 每次raf執(zhí)行的時候插入raf字樣 , 在保證一段scroll過程中只存在唯一一個RAF , 輸出如上圖

事實證明 ios微信環(huán)境下 , raf觸發(fā)的頻率在快速滑動頁面的時候確實高于scroll;

實現(xiàn)

唯一的一個實現(xiàn)難點在于 scrollend如何監(jiān)聽

在每一次scroll的時候 , 開啟一個50ms的定時器 , 定時器認定為scroll結(jié)束 , 但是每次滑動都創(chuàng)建定時器就亂套了 , 所以要在創(chuàng)建定時器之前先清除定時器;

捋一下:

第一次scroll, 清除一個不存在的定時器 , 然后創(chuàng)建定時器 , 50ms之后執(zhí)行的就是scroll結(jié)束

第二次scroll , 清除第一次創(chuàng)建的定時器 , 創(chuàng)建一個定時器 , 50ms之后執(zhí)行的就是scroll結(jié)束

。。。。

最后一次scroll , 清除倒數(shù)第二次創(chuàng)建的定時器 , 創(chuàng)建一個定時器 , 由于沒有下一次scroll了 , 那么這個定時器就真的是最后一次scroll了

于是通過這樣的方案迂回形成了scrollEnd , 雖然有50ms的誤差~

然后代碼如下 :

var rAF = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (callback) { window.setTimeout(callback, 1000 / 60); };

var cancelRAF = window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.webkitCancelRequestAnimationFrame ||
window.mozCancelRequestAnimationFrame ||
window.oCancelRequestAnimationFrame ||
window.msCancelRequestAnimationFrame ||
clearTimeout;


class BetterScroll {
constructor() {
    let sy = window.scrollY;
    this.onScroll = this.onScroll;
    this.onScrollEnd = this.onScrollEnd;
    this.scrollList = [];
    this.scrollEndList = [];
    this.scrollTimer = null;
    this.nowWsy = sy;
    this.lastY  =  sy;
    this.direction = 0;
    this.rafMark = null;
    this.rafingMark = false;
    this.gap = 0;
    this.bindEvent();
}
onScroll(cb) {
    if (typeof cb !== "function") {
        return;
    }
    this.scrollList.push(cb);
}
onScrollEnd(cb) {
    if (typeof cb !== "function") {
        return;
    }
    this.scrollEndList.push(cb);
}
scrollEnd() {
    let winInfo = {
        sy : this.nowWsy,
        gap : Math.abs(this.gap),
        dir : this.direction,
    }
    for (let i = 0, len = this.scrollEndList.length; i < len; i++) {
        try {
            this.scrollEndList[i](winInfo);
        } catch (error) {
            console.warn(error)
        }
    }
}
rafing() {
    this.nowWsy = window.scrollY;
    this.gap = this.nowWsy - this.lastY;
    // 1為向上滑動 -1 為向下滑動
    !!this.gap && (this.direction = (((this.gap >= 0) | 0 ) - 0.5) * 2);
    this.lastY = this.nowWsy;
    let winInfo = {
        sy : this.nowWsy, //當(dāng)前window的scrollY
        gap : Math.abs(this.gap), //上次到這次滑動的距離
        dir : this.direction,  // 滑動方向
        
    }
    for (let i = 0, len = this.scrollList.length; i < len; i++) {
        try {
            this.scrollList[i](winInfo);
        } catch (error) {
            console.warn(error)
        }
    }

    this.startRaf();
}
startRaf() {
    let _this = this;
    this.rafMark = rAF(function () {
        _this.rafing();
    })
}
bindEvent() {
    let _this = this;
    window.addEventListener("scroll", function () {
        clearTimeout(_this.scrollTimer);

        if (!_this.rafingMark) {
            _this.startRaf();
            _this.rafingMark = true;
        }

        _this.scrollTimer = setTimeout(function () {
            cancelRAF(_this.rafMark);
            _this.scrollEnd();
            _this.rafingMark = false;
        }, 50);

    }, 0)
}
}

let btScroll = new BetterScroll();

export default btScroll;

用法 :

組建拋出btScroll對象 , 

提供兩個方法

btScroll.onScroll(callback);  window正在scrolling的函數(shù) , 回調(diào)函數(shù)接受參數(shù) winInfo

btScroll.onScrollEnd(callback); window滑動結(jié)束的函數(shù) , 回調(diào)函數(shù)接受參數(shù) winInfo


winInfo  :  {
    sy : window的scrollY值,
    gap : 上一次scroll到這一次scroll之間的差值絕對值,
    dir : window的滑動方向 1為瀏覽器滾動條向下滾動 , -1為瀏覽器滾動條向上滾動,
}

歡迎各位大大交流 , 有更好的腦洞和哪里寫的不足的地方歡迎留言討論!

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/54466.html

相關(guān)文章

  • 優(yōu)化移動window.onscroll執(zhí)行頻率方案

    摘要:腦洞爆炸的背景最近開發(fā)項目動效開發(fā)越來越多部分動效需要在頁面滑動的時候執(zhí)行一定的效果但是發(fā)現(xiàn)在移動端很多時候頁面滑動的速度快的時候,動效呈現(xiàn)的不穩(wěn)定性越明顯,會不流暢雖然使用的過渡可以從視覺層面解決這個問題,但是并不能根治,于是乎想到了一個 腦洞爆炸的背景 最近開發(fā)項目動效開發(fā)越來越多 ; 部分動效需要在頁面滑動的時候執(zhí)行一定的效果;但是發(fā)現(xiàn)在移動端 很多時候頁面滑動的速度快的時候 ,...

    3fuyu 評論0 收藏0
  • 優(yōu)化移動window.onscroll執(zhí)行頻率方案

    摘要:腦洞爆炸的背景最近開發(fā)項目動效開發(fā)越來越多部分動效需要在頁面滑動的時候執(zhí)行一定的效果但是發(fā)現(xiàn)在移動端很多時候頁面滑動的速度快的時候,動效呈現(xiàn)的不穩(wěn)定性越明顯,會不流暢雖然使用的過渡可以從視覺層面解決這個問題,但是并不能根治,于是乎想到了一個 腦洞爆炸的背景 最近開發(fā)項目動效開發(fā)越來越多 ; 部分動效需要在頁面滑動的時候執(zhí)行一定的效果;但是發(fā)現(xiàn)在移動端 很多時候頁面滑動的速度快的時候 ,...

    lewif 評論0 收藏0
  • 淺談js防抖和節(jié)流

    摘要:防抖和節(jié)流嚴格算起來應(yīng)該屬于性能優(yōu)化的知識,但實際上遇到的頻率相當(dāng)高,處理不當(dāng)或者放任不管就容易引起瀏覽器卡死。 防抖和節(jié)流嚴格算起來應(yīng)該屬于性能優(yōu)化的知識,但實際上遇到的頻率相當(dāng)高,處理不當(dāng)或者放任不管就容易引起瀏覽器卡死。所以還是很有必要早點掌握的。(信我,你看完肯定就懂了) 從滾動條監(jiān)聽的例子說起 先說一個常見的功能,很多網(wǎng)站會提供這么一個按鈕:用于返回頂部。showImg(ht...

    opengps 評論0 收藏0
  • H5下拉刷新和上拉加載實現(xiàn)原理淺析

    摘要:原文鏈接前言在移動端網(wǎng)頁中,下拉刷新和上拉加載更多數(shù)據(jù)的交互方式出現(xiàn)頻率很高,開源社區(qū)也有很多類似的解決方案,如,庫等。 原文鏈接:justrockit.top 前言 在移動端H5網(wǎng)頁中,下拉刷新和上拉加載更多數(shù)據(jù)的交互方式出現(xiàn)頻率很高,開源社區(qū)也有很多類似的解決方案,如iscroll,pulltorefresh.js庫等。下面是對這兩種常見交互基本實現(xiàn)原理的闡述。 實現(xiàn)原理 下拉刷新...

    X1nFLY 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<