动画 匀速动画

483 阅读2分钟

指定步长的动画

首先获取动画距离,使用动画终点 - 动画起点;然后使用一个定时器,每隔一定毫秒数获取当前元素的当前位置累加上步长,再把累加后的位置设置回去。在累加之前判断一下,当前位置是否已经到达了终点,如果到达终点清除定时器,并终止后面的操作。

指定时长的动画

时间时固定的,路程是固定的,所以指定时间的动画关键在于求得速度,即每次定时器执行时元素改变的距离。

回到顶部

  1. 将页面的scrollTop 设为 0
  2. 缓慢回去 - 指定时间
  3. 缓慢回去 - 指定步长
  4. 图片渐现
// 1. 导入工具方法
const {css} = window.utils;

// 2. 获取元素
let img = document.querySelector('.img-con > img');

// 3. 设定定时器启动动画
let timer = setInterval(() => {
  // 3.1 获取当前元素的透明度
  let op = +css(img, 'opacity');
  // 3.2 给透明度累加,并判断累加后的值
  op += 0.01;
  if (op >= 1) {
    clearInterval(timer);
    op = 1;
  }
  // 3.3 把累加后的值设置回去
  css(img, 'opacity', op);
}, 16);
  1. 匀速动画 速度是一定的,时间时固定的,所以最为关键的是求出路程,然后再求出速度
  2. 匀速运动中某一时刻的位置计算
function linear(curTime, begin, change, duration) {
  // 计算匀速运动时,元素某一时刻的位置
  return (change / duration) * curTime + begin;
}
  1. 多方向的匀速动画即元素的多个 js 属性同时变化

封装动画库

// Effect 运动方式
const Effect = {
  Linear: function (curTime, begin, change, duration) {
    return change / duration * curTime + begin;
  }
};

function animate({ele, target = {}, duration = 2000, after}) {
  // 1. 参数校验
  if (!ele || ele.nodeType !== 1) {
    throw TypeError('ele is not a DOM ELEMENT')
  }

  // 2. 准备动画需要的参数
  const {css} = window.utils;

  // 2.1 根据 target 中传入的属性,计算这些属性的起始位置以及这些属性的运动距离
  let begin = {};
  let change = {};

  // 遍历 target 对象
  for (let k in target) {
    if (target.hasOwnProperty(k)) {
      begin[k] = css(ele, k); // 用 css 方法获取元素的起始位置
      change[k] = target[k] - begin[k]; // 获取元素运动的路程
    }
  }

  // 2.2 记录当前时间
  let time = 0;

  // 2.3 设置 interval
  let interval = 16;

  // 3. 创建动画定时器
  ele.timer && clearInterval(ele.timer); // 每次开始新的动画时停止上一次的动画
  ele.timer = setInterval(() => {
    time += interval;

    if (time > duration) {
      css(ele, target);
      clearInterval(ele.timer);
      // 调用钩子函数
      if (typeof after === 'function') {
        after.call(ele); // 让 after 执行,并且把 after 中的 this 修改成 ele
      }
      return;
    }
    let curState = {};
    // 计算当前元素的位置
    for (let k in target) {
      if (target.hasOwnProperty(k)) {
        curState[k] = Effect.Linear(time, begin[k], change[k], duration)
      }
    }
    // 把当前元素的相应的属性设置为当前状态
    css(ele, curState);
  }, interval)

}