学习资源来自慕课网《js动画效果》:http://www.imooc.com/learn/167
这里的缓冲动画指的是非匀速运动的动画,这里以速度动画原型为基础修改代码:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
*{
padding:0;
margin:0;
}
#box{
width:200px;
height:200px;
background:red;
position:relative; /*物体初始必须要有此参数,否则不能实现物体的移动*/
left:-200px;
top:0;
}
#box span{
width:20px;
height:45px;
background:green;
position:absolute;
left:200px;
top:75px;
color:#fff;
text-align:center;
padding-top:10px;
cursor:pointer;
}
</style>
<script type="text/javascript">
window.onload = function(){
var divEle = document.getElementById("box");
divEle.onmouseover = function(){
playBox3(0); //更精简的函数
};
divEle.onmouseout = function(){
playBox3(-200); //更精简的函数
}
}
//定义定时器初始化为null
var timer = null;
//简化参数个数的函数
function playBox3(target){
//先清除之前的定时器,避免开多个定时器造成bug
clearInterval(timer);
var divEle = document.getElementById("box");
var speed = 0;
//简化传参个数,为移动速度赋值
/*if(divEle.offsetLeft > target){
speed = -10;
}else{
speed = 10;
}*/
timer = setInterval(function(){
//非匀速运动的速度计算
var speed = (target - divEle.offsetLeft)/10;
//速度为正时Math.ceil向上取整,速度为负值Math.floor向下取整
//这里必须分情况取整,不然物体运动停止时达不到目标值target
speed = speed > 0?Math.ceil(speed):Math.floor(speed);
if(divEle.offsetLeft == target){ //面板全部移出/移入时,清空定时器,停止运动
clearInterval(timer);
}else{
divEle.style.left = divEle.offsetLeft + speed +"px";
}
console.log(divEle.offsetLeft);
},50); //每个50ms物体匀速运动 speed + "px"
}
</script>
</head>
<body>
<div id="box"><span id="share">分享</span></div>
</body>
</html>
分析:
缓冲动画实现的关键点是speed的计算,且注意对于正负值得处理,速度为正时Math.ceil向上取整,速度为负值Math.floor向下取整。
为什么正时Math.ceil向上取整,速度为负值Math.floor向下取整,当时学习的时候我也想不通,于是把Math.ceil(speed)和Math.floor(speed)拿来进行单独的测试,发现其中的原因。
以Math.ceil(speed)来测试,改动代码(部分)如下:
timer = setInterval(function(){
//非匀速运动的速度计算
var speed = (target - divEle.offsetLeft)/10;
//速度为正时Math.ceil向上取整,速度为负值Math.floor向下取整
//这里必须分情况取整,不然物体运动停止时达不到目标值target
speed = Math.ceil(speed);
if(divEle.offsetLeft == target){ //面板全部移出/移入时,清空定时器,停止运动
clearInterval(timer);
}else{
divEle.style.left = divEle.offsetLeft + speed +"px";
}
console.log(divEle.offsetLeft);
},50); //每个50ms物体匀速运动 speed + "px"
测试结果如下图-1,图-2
图-1
图-2
由图-1可以看出鼠标划入划出,动画停止时,滑动面板并没有完整显示或隐藏,特别是鼠标滑出时,面板停止运动,但是却漏了一点出来,这是bug呀。为什么会出现这样的bug?原因是,面板停止运动时的left值只达到 -4.5px 、-196.4px,而不是0、-200px。我们来分析一下console.log(divEle.offsetLeft)输出的最后的值,即动画停止运动时divEle.offsetLeft的值,以鼠标划入做分析——鼠标划入时,要求面板以动画完整显示整个面板,即面板的 left 的最终值为 0 ,现在面板停止,divEle.offsetLeft为 -5 ,由代码中speed 的计算公式 var speed = (target - divEle.offsetLeft)/10; 可知 ,此时speed 的值为 0.5 ,然后用speed =Math.ceil(speed) 取整 得speed 的值为 0,计算出divEle.style.left = divEle.offsetLeft + speed +"px"; 所以left 的值一直是 -4.5,而定时器一直在运行,所以面板停止运动,实际是left的值每次计算出来都是同一个值,而不是定时器停止运行了:
timer = setInterval(function(){
//非匀速运动的速度计算
var speed = (target - divEle.offsetLeft)/10;
speed = Math.ceil(speed);
if(divEle.offsetLeft == target){ //面板全部移出/移入时,清空定时器,停止运动
clearInterval(timer);
}else{
divEle.style.left = divEle.offsetLeft + speed +"px";
}
console.log(divEle.offsetLeft);
},50); //每个
要解决上面的bug,必须在speed值为负时,采用Math.floor(speed)向上取整,而不是用Math.floor(speed)向下取整造成未达到终点前速度为0了;同理,只使用Math.foor(speed)也会出现此bug,所以需使用 speed = speed > 0?Math.ceil(speed):Math.floor(speed); 做判断取整。