动画历程之滚动的坑

不少时候咱们在web上作动画通常都是选择滚动事件来触发。由于动画须要判断是否处于视口内,或者是否到达某个临界点。而滚动在不一样的浏览器中,不一样操做系统中的实现都有不一样。这些就是咱们须要注意的坑~android

滚动的触发频率

在咱们先入为主的思想中,咱们总以为滚动事件是每PX都会触发。可是事实并不是如此:
下面请看demo:ios

  1. chrome 移动端滑动模拟,速度是比较慢速的滑动。

触发频率
咱们能够看到触发的频率并非按像素的,在时间上,咱们计算可得,间隔大体上是15ms-18ms。而这恰好是每秒60帧的频率。
而在移动端的浏览器或webview中,滚动事件的触发频率也是不一样的。web

  • ios UIwebview (uc qq) 回调事件须要在滚动完成时触发。
在 iOS UIWebViews中, 在视图的滚动过程当中,scroll 事件不会被触发;在滚动结束后,scroll 才会触发. Safari 和 WKWebViews不受此bug影响。--MDN events/scroll
  • Android chrome

android chrome
在咱们滚动的时候,能够看到触发频率比PC上的高。chrome

可是滚动触发事件与滚动距离以及完成的时间有关。有些浏览器还有惯性滚动的处理,因此并不能一律而论说触发必定是每秒60帧的频率
只是想说明,滚动事件的触发频率不是按照PX浏览器

滚动的距离

  • element.scrollTop 属性能够获取或设置一个元素的内容垂直滚动的像素数函数

    • document.body.scrollTopchrome不适用
    • document.documentElement.scrollTop chrome适用
    • 推荐获取滚动值 document.body.scrollTop + document.documentElement.scrollTop 由于二者只有一个生效
  • window.scrollY返回文档在垂直方向已滚动的像素值。IE9不支持

滚动的模拟

由于滚动事件的兼容性,有一些曲线救国的模拟滚动出现啦,固然,会牺牲必定的性能。
在移动端有touch事件,包含:性能

  • touchstart
  • touchend
  • touchmove
  • touchcancel

方向和距离

经过监听start,end事件。对开始和结束时pageX,pageY进行计算来判断滚动的方向,并得到滚动距离。动画

位置的移动

获取方向和距离以后,咱们就能够在touchmove的回调中经过requestAnimationFrame或setTimeout来设置触发的频率(时间间隔)。位置的移动经过改变元素的transform:translate来实现,之因此不使用left,是由于使用CSS3的位置变化会让设备开启硬件加速,性能比使用left高。spa

再说几句

减小回调执行时间

由于滚动事件在大部分设备和浏览器中触发的频率十分高,因此咱们能够经过节流处理来减小滚动事件中回调函数的执行次数。操作系统

减小回调中DOM操做

由于滚动事件的触发很快,相对于DOM的操做是很是迅速的,因此在回调事件中若是对于DOM有很复杂的操做,这时候你会发现一些用户体验很差的现象,好比闪动,卡顿,位置抖动等....可是没办法,有时候要实现这个功能,也只有这一个办法,哭唧唧~~

滚动动画

有时咱们须要作一个返回顶部,或者滚动到页面中的位置的功能。这时候直接改变scrollTop,整个过程会很是的突兀,这时候咱们能够经过Tween.js来实现滚动的ease,easein这些类型的动画。
献上代码:

// 二次方 缓速动画 easeout模式
    /*
    * t {number} 开始时间
     * b {number} 开始位置
     * c {number} 结束位置
     * d {number} 结束时间
     */
    function QuadEaseOut(t, b, c, d) {
        return -c * (t /= d) * (t - 2) + b;
    }
    // 判断是否有requestAnimationFrame
    if (!window.requestAnimationFrame) {
        requestAnimationFrame = function (fn) {
            setTimeout(fn, 17);
        };
    }
    
    /* 
     * target {string} 目标DOM的ID
     */
    function scrollAnimation(target) {
        var startPosition = document.documentElement.scrollTop + document.body.scrollTop;
        var toTarget = document.getElementById(target).offsetTop - startPosition;
        var endTimer = 400;
        var startTimer = 0;
        var step = function () {
            document.documentElement.scrollTop = QuadEaseOut(startTimer, startPosition, toTarget, endTimer);
            document.body.scrollTop = QuadEaseOut(startTimer, startPosition, toTarget, endTimer);
            startTimer += 20;
            if (startTimer <= endTimer) {
                // 继续运动
                requestAnimationFrame(step);
            } else {
                // 动画结束
            }
        };
        step();
    }
相关文章
相关标签/搜索