如果我要从头开始编写它,我会从类似这样的东西开始:
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
函数将使您在长期内的生活变得更加轻松。我提供了一个简单的线性缓动,但其他更复杂的缓动算法也将遵守相同的接口。
另一个需要注意的事情是,超时和间隔不能保证在固定时间运行,因此通常最好设置您希望过渡花费的总时间,然后计算自上次呈现以来经过了多少时间。
此外,如果您正在同时动画化一堆元素,我肯定会将其重构为单个“渲染循环”。对animateTo
的调用将把工作程序推入工作程序队列中,但只有setTimeout
循环计算经过的时间,然后调用每个工作程序,因此您不必担心无数个timeout
闭包浮动。
无论如何,fiddle here
:)
- Šime Vidas