指定步长的动画
首先获取动画距离,使用动画终点 - 动画起点;然后使用一个定时器,每隔一定毫秒数获取当前元素的当前位置累加上步长,再把累加后的位置设置回去。在累加之前判断一下,当前位置是否已经到达了终点,如果到达终点清除定时器,并终止后面的操作。
指定时长的动画
时间时固定的,路程是固定的,所以指定时间的动画关键在于求得速度,即每次定时器执行时元素改变的距离。
回到顶部
- 将页面的scrollTop 设为 0
- 缓慢回去 - 指定时间
- 缓慢回去 - 指定步长
- 图片渐现
// 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);
- 匀速动画 速度是一定的,时间时固定的,所以最为关键的是求出路程,然后再求出速度
- 匀速运动中某一时刻的位置计算
function linear(curTime, begin, change, duration) {
// 计算匀速运动时,元素某一时刻的位置
return (change / duration) * curTime + begin;
}
- 多方向的匀速动画即元素的多个 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)
}