使用原生JS封装一个动画函数

最近一直在忙项目,很少有时间回顾之前的知识,今天刚好要做一个轮播,因为对兼容性有一定的要求,使用了各种插件和库中的轮播,效果都不是很理想,一怒之下,使用原生JS封装了一个轮播组件,其中重要的功能就是一个动画,看了一下以前封装的函数,千疮百孔,又进行了重新封装,先上代码,有详细的备注。

function animate(el, target, step, dtime) {
  /**
   * 参数说明:
   * - el       表示操作的元素对象
   * - target   表示移动的目标距离 单位 px
   * - step     表示步长,即每次移动的距离 单位 px
   * - dtime    表示移动的间隔时间 单位 ms
   */

  // 步长和间隔时间设置了默认值
  step = step || 10;
  dtime = dtime || 30;

  // 判断是否开启定时器,如果有就清除
  if (el.timeId) {
    clearInterval(el.timeId);
    el.timeId = null;
  };

  // 开启一个定时器,并将定时器挂载道当前元素上
  el.timeId = setInterval(function () {
    /**
     * 获取盒子移动前的水平方向的位置(当前位置) - 偏移的位置
     * - 可以使用 el.offsetLeft 获取,但会将外边距也获取到,不精准,不采用
     * - 这里移动实现方式是改变 left的值,保持统一,还是使用 el.style.left 获取
     * - 使用 el.style.left 有个弊端是,若元素对象上最初没有 left 属性时,获取返回的是 NAN
     * - 这种情况只有在第一次会出现,故最开始的时候,还需要判断返回的值,若为 NAN,则重置为 0;如下
     */
    var current = parseInt(el.style.left);
    current = current ? current : 0;

    // 判断目标距离是否小于当前位置,若小于将 步长 变为 负数,让元素反着移动
    if (current > target) {
      step = -Math.abs(step);
    }

    // 当目标距离与当前位置的差距小于步长时,直接当目标的水平位置设置为目标距离,并清除定时器后跳出函数
    if (Math.abs(current - target) < Math.abs(step)) {
      clearInterval(el.timeId);
      el.style.left = target + 'px';
      return;
    }

    // 定时器每执行一次,就让元素移动一个 步长
    el.style.left = current + step + 'px';
  }, dtime)
}

有两个地方需要特别说明:

  1. 计时器的是直接挂载到被操作的元素对象上的 el.timeID 方便复用
  2. 获取当前水平偏移位置时,没使用 offsetLeft,因为当元素存在外边距时会产生误差,故还时使用原生获取left 的,并对不存在的问题做了判断处理。

若有不足或有更好建议的,欢迎留言交流。

posted @ 2019-05-20 10:03  PingWebNotes  阅读(582)  评论(0编辑  收藏  举报