基于時間的動畫函數(shù)是適用于大多數(shù)情況,避免了由于頁面切換造成的動畫不連貫現(xiàn)象,同時jquery內(nèi)部也使用的這種方法。下面是源碼,結(jié)合源碼看一下就明白了。
<script>
var btn=document.getElementsByClassName("button-success")[0];
var dv=document.getElementsByClassName("div")[0];
btn.onclick= function () {
getStyle(dv,"left");
move(dv,2000,{
left:"200",
top:"300",
},"elasticBoth", function () {
console.log(1);
})
}
var move= function (obj,t, JSON, type, fn) {
var startValue={};//獲取其實(shí)值
var startTime=(new Date()).getTime();//獲取起始時間
for(var attr in JSON){
startValue[attr]=0;//初始化一個style對象
if(attr ==="opacity"){
startValue[attr]=Math.round(getStyle(obj,attr)*100);//兼容IE style是opacity的情況
}else{
startValue[attr]=parseInt(getStyle(obj,attr))
}
}
clearInterval(obj.time);//避免多次觸發(fā)造成動畫疊加
obj.time=setInterval(function () {
var nowTime=(new Date()).getTime();//獲取現(xiàn)在時間
var scale=1-Math.max(0,startTime+t-nowTime)/t;//通過tartTime+t-nowTime獲取隨著時間變化的變化率
for(var attr in JSON){//對json形式的style進(jìn)行挨個賦值
var value=Tween[type](scale*t,startValue[attr],JSON[attr]-startValue[attr],t);//Tween用法,這里把時間t設(shè)置為變化量,這樣就可以得到Tween處理后的變化值。
if(attr==="opacity"){
obj.style.filter='alpha(opacity'+value+')';
obj.style.opacity=value/100;
}else{
obj.style[attr]=value+'px';
}
}
if(scale===1){
clearInterval(obj.time);
if(fn){
fn.call(obj);//觸發(fā)回調(diào)
}
}
},30);
}
var getStyle= function (obj, attr) {
if(obj.currentStyle){
return obj.currentStyle[attr];
}else{
return getComputedStyle(obj,false)[attr];
}
}
var Tween = {
linear: function (t, b, c, d){ //勻速
return c*t/d + b;
},
easeIn: function(t, b, c, d){ //加速曲線
return c*(t/=d)*t + b;
},
easeOut: function(t, b, c, d){ //減速曲線
return -c *(t/=d)*(t-2) + b;
},
easeBoth: function(t, b, c, d){ //加速減速曲線
if ((t/=d/2) < 1) {
return c/2*t*t + b;
}
return -c/2 * ((--t)*(t-2) - 1) + b;
},
easeInStrong: function(t, b, c, d){ //加加速曲線
return c*(t/=d)*t*t*t + b;
},
easeOutStrong: function(t, b, c, d){ //減減速曲線
return -c * ((t=t/d-1)*t*t*t - 1) + b;
},
easeBothStrong: function(t, b, c, d){ //加加速減減速曲線
if ((t/=d/2) < 1) {
return c/2*t*t*t*t + b;
}
return -c/2 * ((t-=2)*t*t*t - 2) + b;
},
elasticIn: function(t, b, c, d, a, p){ //正弦衰減曲線(彈動漸入)
if (t === 0) {
return b;
}
if ( (t /= d) == 1 ) {
return b+c;
}
if (!p) {
p=d*0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p/4;
} else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
},
elasticOut: function(t, b, c, d, a, p){ //正弦增強(qiáng)曲線(彈動漸出)
if (t === 0) {
return b;
}
if ( (t /= d) == 1 ) {
return b+c;
}
if (!p) {
p=d*0.3;
}
if (!a || a < Math.abs(c)) {
a = c;
var s = p / 4;
} else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
},
elasticBoth: function(t, b, c, d, a, p){
if (t === 0) {
return b;
}
if ( (t /= d/2) == 2 ) {
return b+c;
}
if (!p) {
p = d*(0.3*1.5);
}
if ( !a || a < Math.abs(c) ) {
a = c;
var s = p/4;
}
else {
var s = p/(2*Math.PI) * Math.asin (c/a);
}
if (t < 1) {
return - 0.5*(a*Math.pow(2,10*(t-=1)) *
Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
}
return a*Math.pow(2,-10*(t-=1)) *
Math.sin( (t*d-s)*(2*Math.PI)/p )*0.5 + c + b;
},
backIn: function(t, b, c, d, s){ //回退加速(回退漸入)
if (typeof s == 'undefined') {
s = 1.70158;
}
return c*(t/=d)*t*((s+1)*t - s) + b;
},
backOut: function(t, b, c, d, s){
if (typeof s == 'undefined') {
s = 3.70158; //回縮的距離
}
return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
},
backBoth: function(t, b, c, d, s){
if (typeof s == 'undefined') {
s = 1.70158;
}
if ((t /= d/2 ) < 1) {
return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
}
return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
},
bounceIn: function(t, b, c, d){ //彈球減振(彈球漸出)
return c - Tween['bounceOut'](d-t, 0, c, d) + b;
},
bounceOut: function(t, b, c, d){
if ((t/=d) < (1/2.75)) {
return c*(7.5625*t*t) + b;
} else if (t < (2/2.75)) {
return c*(7.5625*(t-=(1.5/2.75))*t + 0.75) + b;
} else if (t < (2.5/2.75)) {
return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
}
return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
},
bounceBoth: function(t, b, c, d){
if (t < d/2) {
return Tween['bounceIn'](t*2, 0, c, d) * 0.5 + b;
}
return Tween['bounceOut'](t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
}
}
</script>
Linear:無緩動效果(勻速運(yùn)動);
Quadratic:二次方的緩動;
Cubic:三次方的緩動
Quartic:四次方的緩動;
Quintic :五次方的緩動;
Sinusoidal:正弦曲線的緩動;
Exponential:指數(shù)曲線的緩動;
Circular:圓形曲線的緩動;
Elastic:指數(shù)衰減的正弦曲線緩動;
Back:超過范圍的三次方緩動);
Bounce:指數(shù)衰減的反彈緩動。
每個效果都分三個緩動方式(方法),分別是:
easeIn:從0開始加速的運(yùn)動;
easeOut:減速到0的運(yùn)動;
easeInOut:前半段從0開始加速,后半段減速到0的運(yùn)動。
函數(shù)的四個參數(shù)分別代表:
t--- current time(當(dāng)前時間);
b--- beginning value(初始值);
c--- change in value(變化量);
d---duration(持續(xù)時間)
運(yùn)算的結(jié)果就是當(dāng)前的運(yùn)動路程。可以看到,只有t-current-time是能變化的,這樣就支持了根據(jù)時間來實(shí)現(xiàn)動畫。