js实现匀加速、匀减速

最近看到一个腾讯面试题:实现一个div滑动的动画,由快至慢5s结束(不准用css3)。

思路很简单,按照加速度公式,即可实现。

最终的效果:点击链接

捡起高中知识,上公式:

image.png

  • 可见,只要知道初速度v0,和加速度a,即可知道t秒时刻,路程是多少,即div移动的距离
  • 所以,重点是求出v0初速度、a加速度的值,如下图,分别求取v0和a的过程

image.png

核心逻辑:

  • 支持配置移动距离
  • 支持配置移动时间
//匀加速
function speedUp(div1, totalS, totalT) {
  let v0 = 0;//初速度
  let a =  (2 * totalS) / (totalT *totalT) ; //加速度
  
  let startTime = new Date();
  
  let timer = setInterval(function () {
  
   //计算已经过了多少毫秒
    let dura = (new Date() - startTime) / 1000;
    
    let s =  Math.ceil(v0 * dura + a * dura * dura / 2);
    
    div1.style.left = s+'px';
    
    // if(s >= totalS){//可以按距离来算
    if(dura >= totalT){//也可以按时间来算
    
      clearInterval(timer);
    }
  }, 10)
}

//匀减速
function speedDown(div1, totalS, totalT) {
  let v0 = totalS * 2 / totalT;//初速度
  let a = -1 * (v0 / totalT); //加速度
  let startTime = new Date();
  let timer = setInterval(function () {
    let dura = (new Date() - startTime) / 1000;
    let s =  Math.ceil(v0 * dura + a * dura * dura / 2);
    div1.style.left = s+'px';
    // if(s >= totalS){
    if(dura >= totalT){
      clearInterval(timer);
    }
  }, 10)
}

let totalS = 800;//总距离
let totalT = 3; //总时间
speedUp(div1, totalS, totalT);
复制代码

经过封装及公共代码抽离后的完整demo:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
    div{
        height: 100px;
        width: 100px;
        margin: 10px 0;
        position: relative;
        left: 0;
    }

</style>
<body>

<table>
    <tr>
        <td>
            匀加速:
        </td>
        <td>
            <div id="div1" style="background: skyblue;" ></div>
        </td>
    </tr>
    <tr>
        <td>
            匀减速:
        </td>
        <td>
            <div id="div2" style="background: lightpink;"></div>
        </td>
    </tr>
    <tr>
        <td>
            总路程:
        </td>
        <td>
            <input id="totalS" value="500">px
        </td>
    </tr>
    <tr>
        <td>
            总时长:
        </td>
        <td>
            <input id="totalT" value="2">s
        </td>
    </tr>
</table>


<button type="button" id="button">开始</button>
</body>

<script>
    let totalSDom = document.getElementById('totalS');
    let totalTDom = document.getElementById('totalT');
    let timer1 = null;
    let timer2 = null;
    document.getElementById('button').addEventListener('click', function(){
        console.log("111");
        clearInterval(timer1);
        clearInterval(timer2);

        let totalS = totalSDom.value;//总距离 800px
        let totalT = totalTDom.value; //总时间,单位秒
        let div1 = document.getElementById('div1');
        let div2 = document.getElementById('div2');

         timer1 = speedUp(div1, totalS, totalT);
         timer2 = speedDown(div2, totalS, totalT);
    });


    //匀减速
    function speedUp(div, totalS, totalT) {
        let v0 = totalS * 2 / totalT;//初速度
        let a = -1 * (v0 / totalT); //加速度
        return animation(v0, a, totalT, function(s){
            div.style.left = s+'px';
        });
    }

    //匀加速
    function speedDown(div, totalS, totalT) {
        let v0 = 0;//初速度
        let a =  (2 * totalS) / (totalT *totalT) ; //加速度
        return animation(v0, a, totalT, function(s){
            div.style.left = s+'px';
        });
    }

    /**
     * @param
     * v0: 初速度
     * a: 加速度
     * totalT:总时长
     * callback:回调函数
     * **/
    function animation(v0, a, totalT, callback){
        let startTime = new Date();
        let timer = setInterval(function () {

            //计算已经过了多少毫秒
            let dura = (new Date() - startTime) / 1000;

            //计算出移动的距离
            let s =  Math.ceil(v0 * dura + a * dura * dura / 2);

            //回调
            callback && callback(s);

            // if(s >= totalS){//可以按距离来算
            if(dura >= totalT){//也可以按时间来算
                clearInterval(timer);
            }
        }, 50);
        return timer;
    }


</script>
</html>
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享