很多时候我们在网页上做动画的时候,一般都会选择滚动事件来触发。因为动画需要判断是否在视口内,或者是否到达某个临界点。滚动在不同的浏览器和操作系统中的实现方式不同。这些都是我们需要注意的坑~滚动的触发频率在我们先入为主的思维中,总觉得每次PX都会触发滚动事件。但事实并非如此:请看下面的demo:chrome移动端滑动模拟,速度是比较慢的滑动。我们可以看到触发频率不是每个像素。从时间上来说,我们可以算出间隔大概是15ms-18ms。而这恰好是每秒60帧。在手机浏览器或者webviews中,滚动事件的触发频率也是不一样的。iosUIwebview(ucqq)回调事件需要在滚动完成时触发。在iOSUIWebViews中,滚动事件不会在视图滚动时触发;滚动结束后触发滚动事件。Safari和WKWebViews不受此错误的影响。--MDNevents/scrollAndroidchrome当我们滚动时,我们可以看到触发频率高于PC。但是滚动触发事件与滚动距离和完成时间有关。一些浏览器也处理惯性滚动,所以不能一概而论的是触发器必须以每秒60帧的频率进行。只是说明滚动事件的触发频率并不是根据PX滚动的距离。element.scrollTop属性可以获取或设置一个元素。内容document.body.scrollTopchrome垂直滚动的像素数不适用document.documentElement.scrollTopchrome适用,建议获取滚动值document.body.scrollTop+document.documentElement.scrollTop因为只有其中之一两者生效window.scrollY返回文档在垂直方向滚动的像素值。IE9不支持滚动模拟。因为滚动事件的兼容,所以出现了一些曲线救国的模拟滚动。当然,会牺牲一定的性能。移动端有触摸事件,包括:touchstarttouchendtouchmovetouchcancel通过监听start和end事件取消方向和距离。计算开始和结束的pageX和pageY,确定滚动方向,得到滚动距离。位置移动得到方向和距离后,我们可以在touchmove的回调中通过requestAnimationFrame或setTimeout设置触发频率(时间间隔)。位置的移动是通过改变元素的transform:translate来实现的。之所以不用left,是因为CSS3的positionchange会让设备开启硬件加速,性能比用left要高。多说几句减少回调执行时间因为滚动事件在大多数设备和浏览器中触发的频率都非常高,所以我们可以通过节流来减少滚动事件中回调函数的执行次数。减少回调中的DOM操作,因为scroll事件的触发是非常快的,相对于DOM的操作是非常快的,所以如果回调事件中对DOM有非常复杂的操作,你会发现一些此时的用户体验很差。比如闪烁,卡顿,晃动位置等等。。。但是没办法,有时候只有一种方法可以实现这个功能,哭~~滚动动画有时候我们需要做一个返回顶部,或者滚动到该位置的页面功能。这个时候直接改变scrollTop,整个过程会很突兀。这时候我们就可以使用Tween.js来实现ease、easein等滚动动画。呈现代码://二次方慢动画缓出模式/**t{number}开始时间*b{number}开始位置*c{number}结束位置*d{number}结束时间*/functionQuadEaseOut(t,b,c,d){返回-c*(t/=d)*(t-2)+b;}//判断是否有requestAnimationFrameif(!window.requestAnimationFrame){requestAnimationFrame=function(fn){setTimeout(fn,17);};}/**target{string}目标DOM的ID*/functionscrollAnimation(target){varstartPosition=document.documentElement.scrollTop+document.body.scrollTop;vartoTarget=document.getElementById(target).offsetTop-startPosition;var结束定时器=400;变种开始定时器=0;varstep=function(){document.documentElement.scrollTop=QuadEaseOut(startTimer,startPosition,toTarget,endTimer);document.body.scrollTop=QuadEaseOut(startTimer,startPosition,toTarget,endTimer);启动计时器+=20;if(startTimer<=endTimer){//继续移动requestAnimationFrame(step);}else{//动画结束}};步();}
