当前位置: 首页 > Web前端 > CSS

优化window.onscroll在移动端的执行频率方案

时间:2023-03-30 23:44:48 CSS

脑洞大开的背景。最近开发项目中的动画开发项目越来越多;一些动画效果需要在页面滑动时执行一定的效果;页面快速滑动时,动效的不稳定更加明显,不会流畅;css3的transition虽然可以从视觉层面解决这个问题,但是无法根治,于是想到了解决办法。..requestAnimationFrame(RAF)h5是一个新的刷帧的api。你可以在网上找到很多相关的教程。用法很简单,就像使用setTimeOut一样;“Executetheactionbeforerenderingnextframe”这句话可能会更好地帮助你理解这个API;移动端动画不流畅的解决方法和原因是因为快速滑动时两个startscrolls之间的“间距”越来越大,滑动计算的精度越来越高而且更不准确。当然,我们希望每1px执行一次滚动是最完美的~(虽然基本不可能)所以,我想到了解决办法?!可以在window.scroll启动时开启RAF,在window.scroll结束时关闭RAF。所有需要在scroll中执行的功能都可以移到RAF中去执行。实际上,实验结果是每次window.scroll在页面上插入一次scroll这个词,每次执行raf的时候都插入raf这个词,保证滚动期间只有一个RAF,输出如上图所示。事实证明,在ios微信环境下,raf触发的频率在页面快速滑动时确实比scroll要高;唯一的实现难点在于scrollend如何在每次scroll时监听启动一个50ms的定时器,定时器被认为是scroll结束,但是每次滑动都创建一个定时器就乱七八糟了,所以我们需要在创建定时器之前,清除定时器;看一下:第一次scroll,清除一个不存在的timer,然后创建一个timer,scroll会在50ms后执行,第二次scroll会清除第一次设备创建的timer,创建一个timer,然后50ms后的执行是滚动的结束。...对于最后一个滚动,清除倒数第二个创建的计时器并创建一个计时器。既然没有下一个卷轴,那么这个定时器就真的是最后一个卷轴了。所以scrollEnd是通过这个方案形成的,虽然有50ms的误差~那么代码如下:(回调){window.setTimeout(回调,1000/);};varcancelRAF=window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.webkitCancelRequestAnimationFrame||window.mozCancelRequestAnimationFrame||window.oCancelRequestAnimationFrame||window.msCancelRequestAnimationFrame||clearTimeout;classBetterScroll{constructor(){letsy=windowthis.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;吨他的差距=0;this.bindEvent();}onScroll(cb){if(typeofcb!=='function'){返回;}this.scrollList.push(cb);}onScrollEnd(cb){if(typeofcb!=='function'){返回;}this.scrollEndList.push(cb);}scrollEnd(){letwinInfo={sy:this.nowWsy,gap:Math.abs(this.gap),dir:this.direction,}for(leti=0,len=this.scrollEndList.length;i=0)|0)-0.5)*2);this.lastY=this.nowWsy;letwinInfo={sy:this.nowWsy,//当前窗口的滚动间隙:Math.abs(this.gap),//上一张幻灯片到本张幻灯片的距离dir:this.direction,//滑动方向}对于(让我=0,len=this.scrollList.length;我<伦;i++){尝试{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)}}letbtScroll=newBetterScroll();exportdefaultbtScroll;用法:创建一个btScroll对象,提供两种方法btScroll.onScroll(callback);窗口是滚动功能,回调函数接受参数winInfobtScroll.onScrollEnd(callback);窗口滑动结束函数,回调函数接受参数winInfowinInfo:{sy:窗口的scrollY值,gap:上次滚动和本次滚动的差绝对值,dir:窗口的滑动方向1为浏览器滚动条向下滚动,-1为浏览器滚动条向上滚动,}欢迎大家交流一下,有更好的想法和文中不足的地方,欢迎留言讨论!