用JS模拟transitiontimingfunctioneaseout

10次阅读

共计 3594 个字符,预计需要花费 9 分钟才能阅读完成。

背景:前几天在做项目的过程中需要更改 div 的 scrollTop, 要求运动过程类似 IOS Webview 可视区吸顶动画,先快后慢

分析:

  1. css 不能设置 offsetTop,需要 JS 动态更改 offsetTop。
  2. 动画先快后慢意味着,scrollTop 更改的速度越来越慢
  3. 移动总体的距离是 scrollTop。
  4. 事件控制在两秒之类,小于一屏幕 1s,大于一屏幕 2s
  5. 速度??距离??速度在时间上的积分等于距离????定积分!!!!

猜想函数:

什么函数是递减的??

什么函数做定积分好做。换句话说,原函数好找??

什么函数作用域包涵 0(因为需要从 0 时刻开始)

什么函数在 0 -2S 的积分为 scrollTop

盲猜 y = 1 / x;

绘图地址

作用域不包含 0???向右平移一个单位???左加右减,上加下减!!!哈哈哈哈 高数老师的敦敦教导 = =

y = 1 / (x + 1);

y = 1 / (x + 1); 在 0 -2s 的积分一定是 scrollTop 吗????

需要一个系数????

y = K / (x + 1) ;

怎么求出这个系数呢??

y = K / (x + 1);

y 在 0 – 2 上的积分 = scrollTop;

y = 1 / x 的原函数 f(x) = Math.log(x) + c,c 为常数;

类推求出 y = K / (x + 1)的原函数 f(x) = Math.log(x + 1) + c, c 为常数;

最终实现代码如下:

优化性能
setInterval 实现这种效果只是使用 20ms 作为 offset 更改的时间点
更高的优化????requestAnimFrame!!!MDN requestAnimationFrame

核心思路:获取两次递归的事件间隔???new Date().getTime() – startTime

最终实现如下:


完整代码 
    <!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> 测试 scroll</title>

    <style>

        * {
            padding: 0;
            margin: 0;
        }

        .scroll {
            height: 400px;
            overflow: scroll;
            width: 100px;
            background-color: red;
        }

        .scroll div:nth-child(even) {
            height: 60px;
            background-color: red;
        }

        .scroll div:nth-child(odd) {
            height: 60px;
            background-color: green;
        }

        .button {
            position: fixed;
            right: 0;
            top: 0;
            height: 30px;
            width: 100px;
            background-color: red;
            font-size: 12px;
            line-height: 30px;
            text-align: center;
        }
    </style>

    <script>
        window.addEventListener('load', () => {const scrollDOM = document.querySelector('.scroll');
            const btnDOM = document.querySelector('.button');

            window.requestAnimFrame = window.requestAnimationFrame
                || window.webkitRequestAnimationFrame
                || window.mozRequestAnimationFrame;

            btnDOM.addEventListener('click', () => {console.log(scrollDOM.scrollTop);
                let scrollTop = scrollDOM.scrollTop;

                window.requestAnimFrame
                    ? window.requestAnimFrame(() => requestFrameUpdateScrollTop(new Date().getTime(), scrollTop))
                    : setTimeUpdateScrollTop(scrollTop);
            });

            const requestFrameUpdateScrollTop = (startTime, scrollTop) => {
                const timeStep = 20;
                // 总时间 2000 ms
                const allX = 2000 / timeStep;
                let startX = 0;

                // 系数
                const ratio = scrollTop / Math.log(allX + 1);
                // 定积分可得
                const speed = ratio * (1 / (startX + 1));
                const time = new Date().getTime();
                const timeDiff = time - startTime;
                startX += Math.floor(timeDiff / timeStep) + 1;
                scrollTop = scrollTop - speed * startX;
                scrollTop = scrollTop <= 1 ? 0 : scrollTop;
                scrollDOM.scrollTop = scrollTop;
                if (scrollTop > 0) {window.requestAnimFrame(() => requestFrameUpdateScrollTop(Date.now(), scrollTop));
                }
            };

            const setTimeUpdateScrollTop = scrollTop => {if (this.timer) {return;}

                const timeStep = 20;
                // 总时间 2000 ms
                const allX = 2000 / timeStep;
                let startX = 0;
                // 系数
                const ratio = scrollTop / Math.log(allX + 1);
                // 定积分可得

                this.timer = setInterval(() => {const speed = ratio * (1 / (startX + 1));
                    console.log(speed);
                    startX++;
                    scrollTop = scrollTop - speed;
                    scrollDOM.scrollTop = scrollTop < 0 ? 0 : scrollTop;
                    if (scrollTop <= 0) {clearInterval(this.timer);
                        this.timer = null;
                    }
                }, timeStep);
            };
        });
    </script>
</head>
<body>
<div class="scroll">
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
    <div>asdasd</div>
</div>

<div class="button">
    开始 123123123 运动
</div>
</body>
</html>

这是先快后慢的动画,其他动画的解决思路同理
核心:

 找函数,做积分!!!找函数,做积分!!!找函数,做积分!!!

最后说句:如果能用 css 实现,少用 JS

正文完
 0