匀速动画

  • 预览图

代码

先将通用的html和css代码贴出来

  • html代码
<button class="begin500">开始到500</button>
<button class="begin200">开始到200</button>
<button class="end">结束</button>
<div class="move-box"></div>
<div class="blue-box"></div>
<div class="red-box"></div>
  • css代码
<style>
    .move-box {
      width: 80px;
      height: 80px;
      background-color: #E83733;
      /*margin-left: 40px;*/
    }

    .blue-box {
      width: 500px;
      height: 10px;
      background-color: blue;
    }

    .red-box {
      width: 200px;
      height: 10px;
      background-color: red;
    }
  </style>
  • JavaScript代码
这里主要是编程思想的理解,js代码有几个注意点每次点击启动定时器执行动画前需要关闭定时器,防止多次点击启动多次定时器

IOS 动画匀速加速算法 js匀速动画_移出

其实位置通过getComputedStyle得到,不能直接设置为0,防止默认的marginleft不为0的情况,如marginleft为40px,执行动画时候就会从0开始执行

IOS 动画匀速加速算法 js匀速动画_IOS 动画匀速加速算法_02


如果当前位置已经到达需要移动到的位置或者超过了需要移动到的位置,就停止计时器,并将需要移动到的位置复制给起始位置,防止起始位置超过需要移动到的位置。


IOS 动画匀速加速算法 js匀速动画_css_03

<script>
  // - 获取需要操作的元素
  let oBox = document.querySelector(".move-box");
  let begin500Btn = document.querySelector(".begin500");
  let begin200Btn = document.querySelector(".begin200");
  let endBtn = document.querySelector(".end");
  let timer = null;

  // -- 按钮添加点击事件
  begin500Btn.onclick = function () {
    // - 每次启动定时器前先移出定时器,防止定时器多次执行
    clearInterval(timer);
    // - 每次移动的距离
    let step = 13;
    // - 需要移动到的位置
    let target = 500;
    // - 起始位置
    let begin = parseInt(getComputedStyle(oBox).marginLeft);
    // - 开启定时器
    timer = setInterval(function () {
      // - 使用当前起始位置 + 每次移动距离 = 这次移动的距离
      begin += step;
      /* 如果当前位置已经到达需要移动到的位置或者超过了需要移动到的位置,就停止计时器
       * 并将需要移动到的位置复制给起始位置,防止起始位置超过需要移动到的位置。
       */
      if (begin >= target){
        // - 停止计时器
        clearInterval(timer);
        // - 赋值到起始位置
        begin = target;
      }
      // - 移动位置
      oBox.style.marginLeft = begin+"px";

    },100)

  }

</script>

移动到200事件,这里要从两个方向考虑,从500移动到200以及从0移动到200,这里两种方式计算方式不一样,500到200是marginLeft不断变小,0到200则和0到500一样marginLeft不断变大。
先看下500到200的代码

// -- 按钮添加点击事件
  begin200Btn.onclick = function () {
    // - 每次启动定时器前先移出定时器,防止定时器多次执行
    clearInterval(timer);
    // - 每次移动的距离
    let step = -13;
    // - 需要移动到的位置
    let target = 200;
    // - 起始位置
    let begin = parseInt(getComputedStyle(oBox).marginLeft);
    // - 开启定时器
    timer = setInterval(function () {
      // - 使用当前起始位置 + 每次移动距离 = 这次移动的距离
      begin += step;
      /* 如果当前位置已经到达需要移动到的位置或者超过了需要移动到的位置,就停止计时器
       * 并将需要移动到的位置复制给起始位置,防止起始位置超过需要移动到的位置。
       */
      if (begin <= target){
        // - 停止计时器
        clearInterval(timer);
        // - 赋值到起始位置
        begin = target;
      }
      // - 移动位置
      oBox.style.marginLeft = begin+"px";

    },100)
  }
此处的代码只改变了step、target的值和到达目标位置的判断方法,已经可以实现500到200的功能。

IOS 动画匀速加速算法 js匀速动画_css_04


但是如果要执行0到200是无法完成的,因为判断结束条件是起始位置小于等于目标位置,但是从0到200的起始位置绝对会小于目标位置,所以就会直接执行begin=target,导致无动画效果,瞬移到目标位置。


IOS 动画匀速加速算法 js匀速动画_IOS 动画匀速加速算法_05

  • JavaScript代码改进

移动500到移动200的代码实际相差不了太多,可以将代码封装
解决瞬移问题

begin500Btn.onclick = function () {
    linearAnimation(13,500,oBox);
  }

  begin200Btn.onclick = function () {
    linearAnimation(13,200,oBox);
  }
  
  /* step   每次动画的距离
   * target 需要动画的总距离
   * ele 需要动画的元素
   */
  function linearAnimation(step,target,ele) {
    // - 每次启动定时器前先移出定时器,防止定时器多次执行
    clearInterval(timer);
    // - 起始位置
    let begin = parseInt(getComputedStyle(ele).marginLeft);
    // - 判断是前进还是后退,负为前进,正为后退
    step = begin-target>0?-step:step;
    // - 开启定时器
    timer = setInterval(function () {
      // - 使用当前起始位置 + 每次移动距离 = 这次移动的距离
      begin += step;
      /* 如果当前位置已经到达需要移动到的位置或者超过了需要移动到的位置,就停止计时器
       * 并将需要移动到的位置复制给起始位置,防止起始位置超过需要移动到的位置。
       * 此处是对方法进行封装,所以不能使用之前的方法进行判断,需要定义一种判断,判断两种行为
       * (起始位置 - 规定移动距离)的绝对值 小于等于 step的绝对值,说明已经到了规定的位置了
       */
      if (Math.abs(begin-target) <= Math.abs(step)){
        // - 停止计时器
        clearInterval(timer);
        // - 赋值到起始位置
        begin = target;
      }
      // - 移动位置
      ele.style.marginLeft = begin+"px";

    },100)
  }
  • 最终效果

总结

匀速动画关键步骤是,启动定时器在规定时间了改变元素的位置或者大小,如在100毫秒内改变div的宽度,100毫秒内改变div的top等等。