1.初識動畫css
>JS動畫就是一個定時器,由於定時器的異步因此JS動畫也是異步的,不影響其餘代碼的正常運行,頁面上能夠有不少的動畫,異步
>動畫結束後必定要清理定時器函數
2.固定步長的動畫優化
>固定步長的動畫,固定時間走一步,所以時間是不肯定的動畫
>目標值:一屏幕的寬-盒子的寬ui
>this
//設置一個定時器每隔一段時間(頻率,定時器的第二個參數),走一步(步長step)
//到達目標值清除定時器
var maxL=$.win("clientWidth")-box.offsetWidth;
//設置步長
var step=5;
var timer=setInterval(()=>{
//先獲取當前left值
var l=$.css(box,"left");
//加上步長
l+=step;
//若是最後一步不夠步長,若是走了這一步就會超出最大值,因此說最後一步咱們幫他走 ,到達臨界值時候直接將最值賦給box便可
if(l>=maxL){
clearInterval(timer);
// $.css(box,"left",maxL);
// //加return就是不讓他走最後一步
// return;
l=maxL;
}
//再給box設置加以後的left值
$.css(box,"left",l);
},20)
3.總時間肯定的動畫prototype
>動畫不只可讓left值改變,也可讓top,height,width,opacity都有動畫效果,對象
>惟有不變的是總時間ci
>總時間duration是設置的 :2000
>left的目標值是target:
$.win("clientWidth")-box.offsetWidth
>opacity的target:1
>left的總路程=target-begin
>left步長step須要計算:每一段時間內(頻率,定時器的第二個參數)走的距離
>速度=總路程/總時間,這裏是單位時間內走的距離,這裏就是每一毫秒走的距離
>step=速度*頻率=
(target-begin)/duration * interval
>
let box=document.getElementById("box");
let duration=2000;
let target=$.win("clientWidth")-box.offsetWidth;
let begin=$.css(box,"left");
let interval=20;
let step=interval*(target-begin)/duration;
timer=setInterval(()=>{
begin+=step;
if(begin>=target){
clearInterval(timer);
}
$.css(box,"left",begin);
},interval);
4.勻速直線運動
>讓left的值不斷變化,time是這裏惟一的變量
當前left=起始位置+走過的距離
=begin+速度*時間
=begin+總距離/總時間 *時間
=begin+(target-begin)/duration *time
>
function linear(begin,target,duration,time) {
return begin+(target-begin)/duration *time
}
var duration=2000;
var begin=$.css(box,"left");
var target=$.win("clientWidth")-box.offsetWidth;
var interval=20, time=0;
var timer=setInterval(()=>{
//惟一的變量就是time,每一次加的時間間隔是interval
time+=interval;
//時間到了清除定時器
if(time>=duration){
clearInterval(timer);
time=duration;
}
//利用公式求出當前left,賦給box的left
$.css(box,"left",linear(begin,target,duration,time));
},interval)
5.多維動畫
>實現width,height,top,left,opacity五個維度的變化,這五個維度的起始位置,目標值都不同,
>若是變量太多不利於優化,因此將begin與target都寫成對象的形式
>
var duration=2000;
var begin={
width:box.offsetWidth,
height:box.offsetHeight,
top:$.css(box,"top"),
left:$.css(box,"left"),
opacity:0
};
var target={
width:300,
height:200,
//注意:這裏最大值要減去改變後的寬和高
top:$.win("clientHeight")-200,
left:$.win("clientWidth")-300,
opacity:1
};
var time=0,interval=20,timer=null;
function linear(begin,target,duration,time) {
return begin+(target-begin)/duration*time;
}
timer=setInterval(()=>{
time+=interval;
//臨界值判斷
if(time>=duration){
clearInterval(timer);
time=duration;
}
//循環target求出每一個維度的linear函數的值
for (var key in target){
$.css(box,key,linear(begin[key],target[key],duration,time))
}
},interval);
6.動畫完成以後的操做,增長新的內容
var duration=3000;
var begin={
width:0,
height:0,
left:0,
opacity:0
};
var target={
width:100,
height:100,
left:1000,
opacity:1
};
var time=0,interval=20,timer=null;
function linear(b,t,d,time) {
return b+(t-b)/d*time
};
timer=setInterval(()=>{
time+=interval;
if(time>=duration){
clearInterval(timer);
//既然想要這裏完成動畫if外面的代碼就不能夠執行了,此時加上一個return,可是加上return以後就少了一步此時咱們幫他完成最後一步便可,最後一步其實就是讓每個維度到達目標值
for(var key in target){
$.css(box,key,target[key])
}
//走完最後一步,在這裏動畫完成,之後動畫完成的操做寫在這裏便可
box.className="box";
return;
}
for (var key in target){
$.css(box,key,linear(begin[key],target[key],duration,time))
}
},interval)
7.往返運動
var t = 1000;
var b = 0;
var interval = 20;
function linear(b, t, d, time) {
return b + (t - b) / d * time
};
function go() {
var d = 1000;
var time = 0;
timer=setInterval(()=>{
time+=interval;
if(time>=d){
clearInterval(timer);
$.css(box,"left",t);
//當前go完成,執行back
back();
return;
}
$.css(box,"left",linear(b,t,d,time))
},interval);
}
function back() {
var d=3000;
var time=0;
timer=setInterval(()=>{
time+=interval;
if(time>=d){
clearInterval(timer);
$.css(box,"left",b);
//back完成,執行go
go();
return;
}
$.css(box,"left",linear(t,b,d,time))
},interval);
}
go();
8.動畫的初步封裝
function animation(curEle,target={},duration=2000,interval=13,effect=0,callback) {
//curEle:當前執行動畫的元素
//target:目標位置 對象例如{left:1000,top:400,width:300}
//duration:總時間
//interval:頻率
//effect:運動曲線
//callback:動畫完成以後執行的函數
//處理callback,沒傳或者是傳的不是一個函數了,後面讓他執行就報錯了,讓他等於一個空函數便可
if(typeof callback!="function"){
callback=function () {};
}
//設置其餘變量
var time=0,timer=null,begin={};
//根據target給begin賦值
//target必須存在而且是一個對象
if(target&&target.toString()=="[object Object]"){
for(var key in target){
begin[key]=$.css(curEle,key);
}
};
//處理運動曲線
function linear(t, b, c, d) {
return c * t / d + b;
};
function QuadEaseIn(t, b, c, d) {
return c * (t /= d) * t + b;
};
function QuadEaseOut(t, b, c, d) {
return -c * (t /= d) * (t - 2) + b;
};
var effectAry=[linear,QuadEaseIn,QuadEaseOut];
effect=effectAry[effect];
//開啓定時器執行動畫
timer=setInterval(()=>{
time+=interval;
if(time>=duration){
clearInterval(timer);
for (var key in target){
$.css(curEle,key,target[key]);
}
//讓 callback中的this變成當前元素
callback.call(curEle);
return;
};
for(var key in target){
$.css(curEle,key,effect(time,begin[key],target[key]-begin[key],duration));
}
},interval);
};
animation(box,{width:150,height:150,left:1200,top:400},3000,17,1,function () {
this.style.backgroundColor="green";
});
9.封裝升級
Element.prototype.animation=function (target,...arg) { //this :當前執行動畫的元素 target=target||{}; let begin={}, duration=2000, interval=13, effect=0, time=0, timer=null, numAry=[], fnAry=[], EffectAry=[]; arg.forEach((item)=>{ if(typeof item=="number"){ numAry.push(item); }else if(typeof item=="function"){ fnAry.push(item); } }); for (let i=0;i<numAry.length;i++){ if(numAry[i]>100){ duration=numAry[i]; numAry.splice(i,1); break; } }; interval=numAry[0]?numAry[0]:interval; effect=numAry[1]?numAry[1]:effect; for(let key in target){ begin[key]=$.css(this,key); }; let Effect = { //勻速 Linear: function (t, b, c, d) { return c * t / d + b; }, //指數衰減的反彈緩動 BounceEaseIn: function (t, b, c, d) { return c - Effect.BounceEaseOut(d - t, 0, c, d) + b; }, BounceEaseOut: 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 + .75) + b; } else if (t < (2.5 / 2.75)) { return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b; } else { return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b; } }, BounceEaseInOut: function (t, b, c, d) { if (t < d / 2) { return Effect.BounceEaseIn(t * 2, 0, c, d) * .5 + b; } return Effect.BounceEaseOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b; }, //二次方的緩動 QuadEaseIn: function (t, b, c, d) { return c * (t /= d) * t + b; }, QuadEaseOut: function (t, b, c, d) { return -c * (t /= d) * (t - 2) + b; }, QuadEaseInOut: function (t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t + b; } return -c / 2 * ((--t) * (t - 2) - 1) + b; }, //三次方的緩動 CubicEaseIn: function (t, b, c, d) { return c * (t /= d) * t * t + b; }, CubicEaseOut: function (t, b, c, d) { return c * ((t = t / d - 1) * t * t + 1) + b; }, CubicEaseInOut: function (t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t + b; } return c / 2 * ((t -= 2) * t * t + 2) + b; }, //四次方的緩動 QuartEaseIn: function (t, b, c, d) { return c * (t /= d) * t * t * t + b; }, QuartEaseOut: function (t, b, c, d) { return -c * ((t = t / d - 1) * t * t * t - 1) + b; }, QuartEaseInOut: 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; }, //五次方的緩動 QuintEaseIn: function (t, b, c, d) { return c * (t /= d) * t * t * t * t + b; }, QuintEaseOut: function (t, b, c, d) { return c * ((t = t / d - 1) * t * t * t * t + 1) + b; }, QuintEaseInOut: function (t, b, c, d) { if ((t /= d / 2) < 1) { return c / 2 * t * t * t * t * t + b; } return c / 2 * ((t -= 2) * t * t * t * t + 2) + b; }, //正弦曲線的緩動 SineEaseIn: function (t, b, c, d) { return -c * Math.cos(t / d * (Math.PI / 2)) + c + b; }, SineEaseOut: function (t, b, c, d) { return c * Math.sin(t / d * (Math.PI / 2)) + b; }, SineEaseInOut: function (t, b, c, d) { return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b; }, //指數曲線的緩動 ExpoEaseIn: function (t, b, c, d) { return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b; }, ExpoEaseOut: function (t, b, c, d) { return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b; }, ExpoEaseInOut: function (t, b, c, d) { if (t == 0) return b; if (t == d) return b + c; if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b; return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b; }, //圓形曲線的緩動 CircEaseIn: function (t, b, c, d) { return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b; }, CircEaseOut: function (t, b, c, d) { return c * Math.sqrt(1 - (t = t / d - 1) * t) + b; }, CircEaseInOut: function (t, b, c, d) { if ((t /= d / 2) < 1) { return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b; } return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b; }, //超過範圍的三次方緩動 BackEaseIn: function (t, b, c, d, s) { if (s == undefined) s = 1.70158; return c * (t /= d) * t * ((s + 1) * t - s) + b; }, BackEaseOut: function (t, b, c, d, s) { if (s == undefined) s = 1.70158; return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; }, BackEaseInOut: function (t, b, c, d, s) { if (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; }, //指數衰減的正弦曲線緩動 ElasticEaseIn: function (t, b, c, d, a, p) { if (t == 0) return b; if ((t /= d) == 1) return b + c; if (!p) p = d * .3; var s; !a || a < Math.abs(c) ? (a = c, s = p / 4) : 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; }, ElasticEaseOut: function (t, b, c, d, a, p) { if (t == 0) return b; if ((t /= d) == 1) return b + c; if (!p) p = d * .3; var s; !a || a < Math.abs(c) ? (a = c, s = p / 4) : 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); }, ElasticEaseInOut: function (t, b, c, d, a, p) { if (t == 0) return b; if ((t /= d / 2) == 2) return b + c; if (!p) p = d * (.3 * 1.5); var s; !a || a < Math.abs(c) ? (a = c, s = p / 4) : s = p / (2 * Math.PI) * Math.asin(c / a); if (t < 1) return -.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) * .5 + c + b; } }; for(let key in Effect){ EffectAry.push(Effect[key]) }; effect=EffectAry[effect=effect>=EffectAry.length?0:effect]; timer=setInterval(()=>{ time+=interval; if(time>=duration){ clearInterval(timer); for (let key in target){ $.css(this,key,target[key]); } fnAry.forEach((item)=>{ item.call(this); }); return; } for(let key in target){ $.css(this,key,effect(time,begin[key],target[key]-begin[key],duration)); } },interval); return this;};