所谓的缓动动画就是在动画的基础上,使元素的速度缓慢增加或缓慢减小的过程(减速或加速),那它使得盒子速度缓慢减小的原理是什么呢??很简单,可以理解为定时器每次进行一次,都执行:当前的距离+变化的步长,首先我们需要一个公式:
这个公式就是每次当前距离要加 的 不断变化的步长,我们称其为步长公式:(目标值-当前位置)/ 10 (这个10可以改)
步长公式的理解:
第一次增加的步长:
假设目标值为到 800px 时停止
第二次增加的步长:
第三次增加的步长:
后面的几步同理以此类推,达到了步长递减的效果,从而达到减速的效果,当距离左边的距离等于目标距离时清除定时器停止即可。
一:代码案例:
让盒子不断减速到目标位置800px处,如图所示:
JS实现:
<script>
document.addEventListener('DOMContentLoaded',function(){
var box=document.querySelector('div');
var btn=document.querySelector('button');
function run(obj,long){
clearInterval(obj.timer)
obj.timer=setInterval(function(){
if(obj.offsetLeft==long){ //左边距离与目标距离一样时就停止(清除定时器)
window.clearInterval(obj.timer);
}else{
step=(long-box.offsetLeft)/10 //步长公式
obj.style.left=obj.offsetLeft+step+'px';
}
},20)
}
btn.addEventListener('click',function(){
run(box,800)
})
})
</script>
但是这样还是存在一个弊端,就是我们目标是停在800px处,但我们可以看到却停在了795.5px,这是因为我们求步长时存在除不尽取小数的问题,这时要解决这个问题我们就要采取:向上转型(Math.ceil)即可
改进代码:
<script>
document.addEventListener('DOMContentLoaded',function(){
var box=document.querySelector('div');
var btn=document.querySelector('button');
function run(obj,long){
clearInterval(obj.timer)
obj.timer=setInterval(function(){
if(obj.offsetLeft==long){
window.clearInterval(obj.timer);
}else{
step=Math.ceil((long-box.offsetLeft)/10)
obj.style.left=obj.offsetLeft+step+'px';
}
},20)
}
btn.addEventListener('click',function(){
run(box,800)
})
})
</script>
这样就可以得到和目标值一样的移动距离啦 !
案例补充说明:
其次,我们这个案例用了步长公式就可以完成向后退的效果了,原理是得到了负的 step 值,这样当前距离 + 步长其实是一个减法,就可以往回退了,这里同样还是要注意小数转型的问题,刚才正步长相加是向上转型,现在减负步长我们要使用向下转型。这里我们可以增加一个三元运算符判断步长正负来选择使用向上还是向下转型: step=step>0?Math.ceil(step):Math.floor(step)
<body>
<script>
document.addEventListener('DOMContentLoaded',function(){
var box=document.querySelector('div');
var btn800=document.querySelector('.go800');
var btn500=document.querySelector('.go500');
function run(obj,long){
clearInterval(obj.timer)
obj.timer=setInterval(function(){
if(obj.offsetLeft==long){
window.clearInterval(obj.timer);
}else{
step=(long-box.offsetLeft)/10
step=step>0?Math.ceil(step):Math.floor(step) //判断步长正负来选择使用哪个转型
obj.style.left=obj.offsetLeft+step+'px';
}
},20)
}
btn500.addEventListener('click',function(){
run(box,500)
})
btn800.addEventListener('click',function(){
run(box,800)
})
})
</script>
<div></div>
<button class="go800">到800</button>
<button class="go500">到500</button>
</body>
以上问题就可以得到完美解决!!
二:下一个问题是给缓动动画添加回调函数,简单的目标效果是当定时器停止,即盒子到达目标位置后,让盒子变色或其他效果,这时就需要我们添加回调函数啦
我们要在调用 动画函数 的参数里添加一个 变色回调函数 作为实参(以第一个动画函数调用为例)
//第一个动画函数的调用
btn500.addEventListener('click',function(){
run(box,500,function(){
box.style.backgroundColor='red';
})
})
然后动画函数的形参需要有一个值来接收,我们命名该形参为 callback,接收后当函数调用时相当于执行了一步:callback=function(){},然后因为我们目标是在停下之后变色,所以这个函数的调用应该放在定时器结束判断条件之后
if(callback){ //如果有回调函数实参传入,就执行回调函数,没有就不执行
callback();
}
完整代码为:
<body>
<script>
document.addEventListener('DOMContentLoaded',function(){
var box=document.querySelector('div');
var btn800=document.querySelector('.go800');
var btn500=document.querySelector('.go500');
var btn0=document.querySelector('.go0')
function run(obj,long,callback){
clearInterval(obj.timer)
obj.timer=setInterval(function(){
if(obj.offsetLeft==long){
window.clearInterval(obj.timer);
if(callback){
callback();
}
}else{
step=(long-box.offsetLeft)/10
step=step>0?Math.ceil(step):Math.floor(step)
obj.style.left=obj.offsetLeft+step+'px';
}
},20)
}
btn500.addEventListener('click',function(){
run(box,500,function(){
box.style.backgroundColor='red';
})
})
btn800.addEventListener('click',function(){
run(box,800)
})
btn0.addEventListener('click',function(){
run(box,0)
})
})
</script>
<div></div>
<button class="go800">到800</button>
<button class="go500">到500</button>
<button class="go0">到原位</button>
</body>