要求如下:
可以開始、暫停(線性、非線性tween都支持)、繼續、結束
支持多個樣式並行
最好不依賴於某個框架下運行
文件尺寸越小越好
他找了一下現有的一些插件或者庫,鮮有能滿足或者比較均衡的,我在這個要求下,寫了一個比較簡陋的動畫組件,基本滿足了這個需求。先上代碼
在線演示:http://demo.jb51.net/js/2012/animate/
打包下載:animate_jquery.rar
html部分:
復制代碼 代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>animate</title>
<script type="text/javascript" src="tangram-1.5.0.core.js"></script>
<script type="text/javascript" src="jquery.min.js"></script>
<style>
html,body,ul,li{padding:0;margin:0;}
#anim{width:50px;height:50px;background:red;position:absolute; top:30px;left:0;}
</style>
</head>
<body>
<div>
<input type="button" value="start" onclick="an.start()" />
<input type="button" value="pause" onclick="an.pause()" />
<input type="button" value="resume" onclick="an.resume()" />
<input type="button" value="stop" onclick="an.stop()" />
<a target="_self" id="demolink" href="animate.html?demo=1" />auto start,pasue,then resume</a>
</div>
<div id="anim"></div>
</body></html>
animate部分:
復制代碼 代碼如下:
function animate(options){
this.from = options.from;//如果沒有from,就計算出from
this.to = options.to || {};
this.onStart = options.onStart || empty;//以下是一些回調函數,就不采用事件機制了
this.onStop = options.onStop || empty;
this.onAnimate = options.onAnimate || empty;
this.onContinue = options.onContinue || empty;
this.onPause = options.onPause || empty;
var element = options.element;
var duration = options.duration || 300;//變化的總時長,單位是ms
var pending = false;//是不是已經暫停了,如果還木有開始的話,該值也是true
var timer = null;
var mixin = options.mix;
var defaultState = this.from || getState(element, this.to);//原始的數據
var thiz = this;
//獲取最初始的樣式
function getState(ele, targetStyles){
var obj = {};
var i = 0;
for (var p in targetStyles)
{
i++;
obj[p] = parseFloat(mixin.getStyle(ele, p));
}
if(i == 0){
return null;
}
return obj;
}
function empty(){}
function animate(from, to, elapse){
var startTime = (new Date).getTime() + (elapse ? - elapse : 0);//如果有第三個參數,證明是從一個暫停開始的,那麼就設置startTime為當前時間減去暫定時已經逝去的時間,如果只有兩個參數,那麼逝去時間就是0
timer = setInterval(function(){
var endTime = (new Date).getTime();
if(endTime - startTime < duration){
thiz.onAnimate();
currentElapse = endTime - startTime;
for(var p in from){
if(from.hasOwnProperty(p)){
var currentPropertyStyle = mixin.compute(currentElapse, from[p], to[p]-from[p], duration);
mixin.setStyle(element, p, currentPropertyStyle);
}
}
}
else{
thiz.stop(thiz.to);
}
}, 16);
}
this.start = function(){
if(pending){
this.resume();
}
else{
this.onStart();
animate(defaultState, this.to);
}
}
this.stop = function(){
clearInterval(timer);
var styles = this.to;
for(var p in styles){
if(styles.hasOwnProperty(p)){
mixin.setStyle(element, p, styles[p]);
}
}
this.onStop();
}
this.pause = function(){
clearInterval(timer);
pending = true;
this.onPause();
}
this.resume = function(){
pending = false;
this.onContinue();
animate(defaultState, this.to, currentElapse);
}
}
使用部分:
復制代碼 代碼如下:
var mixinT = {
getStyle:baidu.dom.getStyle,
setStyle:baidu.dom.setStyle,
compute:function(t, b, c, d){
//return t*c/d + b;
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;
}
};
var mixinJQ = {
getStyle:function(ele, styleName){
return $(ele).css(styleName);
},
setStyle:function(ele, styleName, styleValue){
$(ele).css(styleName, styleValue);
},
compute:function(t, b, c, d){
return b+ t*c/d;
}
};
var an = new animate({
element:document.getElementById('anim'),
//from:{'width':100, 'height':100, left:0, top:30},
to:{left:500},
mix:mixinT,
duration:2000
});
if(/demo=1/.test(location.search)){
var demolink = baidu.g('demolink');
demolink.href= 'animate.html';
demolink.innerHTML = 'back';
an.start();
setTimeout(function(){
an.pause();
resume();
}, 1200);
function resume(){
setTimeout(function(){an.resume()}, 1000);
}
}
上面是一個完整demo的代碼。做幾點說明:
代碼尺寸足夠小了,一共才100行,gzip後連1k都不到。
滿足了可以start、pause、resume、stop的需求,贈送了幾個回調函數:D。
可以支持多個樣式一起變化。
采用了一個mixin變量,傳進來三個函數需要在執行動畫時的操作,getStyle、setStyle、compute,我感覺這三個確實和用戶的選擇有關系,前兩個可能和框架有關,第三個和用戶采用的變化計算方式有關,之所以傳進去四個參數,主要是和主流的tween類能適應起來,可以參考http://www.robertpenner.com/easing/和http://www.actionscript.org/resources/articles/170/1/Flash-MX-2004-Undocumented-TweenEasing-Classes-Documented/Page1.html。我給的例子用了tangram和jquery倆類庫,分別對應了兩個mixin對象,做一下簡單的適配,就能用了。
一些“私有”變量和函數放閉包裡了,這樣初始化一個animate的時候,對象是干淨的,但是缺點就是占用內存多了,每個實例都維護自己的方法。
使用的時候,可以不提供options.from,函數會根據額options.to來計算from中對應樣式的值,這很大程度上依賴於mixin提供的方法夠不夠強大,所以這一塊還是有bug 的,不過,80%的功能夠用了。麻雀雖小,五髒俱全了。