如果我要从头开始编写它,我会从以下内容开始:
function linearEase(start, end, percent) {
return start + ((end - start) * percent);
}
function animateTo(settings) {
var elem = settings.element;
var ease = settings.ease;
var start = { left: elem.offsetLeft, top: elem.offsetTop };
var lastTime = new Date().getTime();
var timeLeft = settings.totalTime;
function update() {
var currentTime = new Date().getTime();
var elapsed = currentTime - lastTime;
timeLeft -= elapsed;
lastTime = currentTime;
var percentDone = 1 - timeLeft/settings.totalTime;
elem.style.top = ease(start.top, settings.top, percentDone) + "px" ;
elem.style.left = ease(start.left, settings.left, percentDone) + "px" ;
if(timeLeft > 0) {
setTimeout(update, 33);
}
}
update();
}
例如,在接下来的两秒内将 div 移动到 (50,50)。
var elem = document.getElementById("animatable");
setTimeout(function() {
animateTo({
element: elem,
left: 50,
top: 50,
totalTime: 2000,
ease: linearEase
})
}, 10);
这是做这类事情的相当标准的模式。获取元素位置和设置样式的东西肯定可以更好地实现。但是从长远来看,抽象出一个ease 函数会让你的生活变得更轻松。我提供了一个简单的线性缓动,但其他更复杂的缓动算法将遵循相同的接口。
另外需要注意的是,超时和间隔是not guaranteed 在设定的时间运行,因此通常最好设置您希望过渡运行的总时间,然后计算出有多少时间自上次渲染以来已过去。
此外,如果您同时为一堆元素设置动画,我肯定会将其重构为单个“渲染循环”。对animateTo 的调用会将工作人员推入工作人员队列,但只有setTimeout 循环计算经过的时间然后调用每个工作人员,因此您没有大量的timeout 闭包浮动。
不管怎样,摆弄here