资讯专栏INFORMATION COLUMN

动画历程之滚动的坑

asce1885 / 3029人阅读

摘要:很多时候我们在上做动画一般都是选择滚动事件来触发。而在移动端的浏览器或中,滚动事件的触发频率也是不同的。在中在视图的滚动过程中,事件不会被触发在滚动结束后,才会触发和不受此影响。但是滚动触发事件与滚动距离以及完成的时间有关。

很多时候我们在web上做动画一般都是选择滚动事件来触发。因为动画需要判断是否处于视口内,或者是否到达某个临界点。而滚动在不同的浏览器中,不同操作系统中的实现都有不同。这些就是我们需要注意的坑~

滚动的触发频率

在我们先入为主的思想中,我们总觉得滚动事件是每PX都会触发。但是事实并非如此:
下面请看demo:

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


我们可以看到触发的频率并不是按像素的,在时间上,我们计算可得,间隔大致上是15ms-18ms。而这刚好是每秒60帧的频率。
而在移动端的浏览器或webview中,滚动事件的触发频率也是不同的。

ios UIwebview (uc qq) 回调事件需要在滚动完成时触发。

在 iOS UIWebViews中, 在视图的滚动过程中,scroll 事件不会被触发;在滚动结束后,scroll 才会触发.  Safari 和 WKWebViews不受此bug影响。--MDN events/scroll

Android chrome


在我们滚动的时候,可以看到触发频率比PC上的高。

但是滚动触发事件与滚动距离以及完成的时间有关。有些浏览器还有惯性滚动的处理,所以并不能一概而论说触发一定是每秒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高。

再说几句 减少回调执行时间

因为滚动事件在大部分设备和浏览器中触发的频率十分高,所以我们可以通过节流处理来减少滚动事件中回调函数的执行次数。

减少回调中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();
    }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95779.html

相关文章

  • 动画历程滚动的坑

    摘要:很多时候我们在上做动画一般都是选择滚动事件来触发。而在移动端的浏览器或中,滚动事件的触发频率也是不同的。在中在视图的滚动过程中,事件不会被触发在滚动结束后,才会触发和不受此影响。但是滚动触发事件与滚动距离以及完成的时间有关。 很多时候我们在web上做动画一般都是选择滚动事件来触发。因为动画需要判断是否处于视口内,或者是否到达某个临界点。而滚动在不同的浏览器中,不同操作系统中的实现都有不...

    Darkgel 评论0 收藏0
  • 动画历程滚动的坑

    摘要:很多时候我们在上做动画一般都是选择滚动事件来触发。而在移动端的浏览器或中,滚动事件的触发频率也是不同的。在中在视图的滚动过程中,事件不会被触发在滚动结束后,才会触发和不受此影响。但是滚动触发事件与滚动距离以及完成的时间有关。 很多时候我们在web上做动画一般都是选择滚动事件来触发。因为动画需要判断是否处于视口内,或者是否到达某个临界点。而滚动在不同的浏览器中,不同操作系统中的实现都有不...

    Blackjun 评论0 收藏0
  • vue(1)-学习历程vue解决jquery的什么痛点

    摘要:解决的痛点首先我们需要明白和理解和的设计初衷和理念。所有框架要解决的问题应对需求变化,防止大面积重写。参考文献渐进式框架理解核心功能原理解析百度网盘视频学习以及源码资源提取密码 vue解决jquery的痛点 首先我们需要明白和理解jquery和vue的设计初衷和理念。 jquery官网给出的开篇介绍是,jquery是一个快,小,功能丰富的js库,它让html文档遍历和操作,事件处理...

    zhaofeihao 评论0 收藏0
  • 指尖一点歌声来--微信小程序仿网易云音乐心得

    摘要:为了提高自己,最近在学习微信小程序,选题是仿网易云音乐。查文档发现,小程序中图片加载完成后,有一个加载完成事件。前者在微信客户端版本就不开始维护了,后者低版本需做兼容处理。目前还有一些功能暂未实现,会在以后继续完善项目,继续学习。 为了提高自己,最近在学习微信小程序,选题是仿网易云音乐。期间踩过了大把的坑,bug出现的难受和解决bug欢喜,一直是伴随我阶段性学习这个项目的心情。初步完成...

    KitorinZero 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<