【原生JS元件】javascript 運動框架
大家都知道JQuerry有animate方法來給DOM元素進行運動,CSS3中也有transition、transform來進行運動。而使用原生的Javascript來控制元素運動,需要寫很多運動的細節以及相容。
然而,當你的BOSS不讓你使用龐大的JQ框架,而且你開發的產品也需要在一些不相容CSS3的瀏覽器執行的時候,你是否覺得每次都要開個定時器來琢磨運動該怎麼進行,是件很費力的事情呢?
那麼福利來了,筆者最近總結了兩個常用的運動框架,並將其寫成元件,
只要按照下面的方法呼叫,即可方便使用。
1.在你的頁面中引入js
<script src="Mover.js"></script >
2.在你的js程式碼中建立Mover物件
<script>
window.onload=function(){
var mover = new Mover();
};
</script>
3.開始使用mover!
用法說明:筆者寫的元件包含了兩種運動框架供使用,一種是基於速度的;一種是基於時間的,讓我們來先看看基於速度的運動框架的用法
startMoveBySpeed(obj, json, endFn);
引數obj : 傳入要運動的物件
引數json : 以json的形式傳入要運動的屬性,包括left、top、width、height等以px為單位的屬性和透明度opacity,他們的值是運動的終點
引數endFn(可選) : 結束運動後要執行的方法
<script>
//基於速度的運動框架用法
window.onload=function(){
//得到你要運動的元素
var oDiv = document.getElementsByTagName('div')[0];
//使用運動框架
var mover = new Mover();
oDiv.onclick=function(){
mover.startMoveBySpeed(this,{'left':200,'width':300,'opacity':50});
//使oDiv的left運動到200px,寬度變為300px,透明度變為50%
}
};
</script>
讓我們來看看另外一種基於時間的運動框架
startMoveByTime(obj, json, options, endFn )
引數obj : 傳入要運動的物件
引數json : 以json的形式傳入要運動的屬性,包括left、top、width、height等以px為單位的屬性和透明度opacity,他們的值是運動的終點
引數options : 以json的形式傳入傳入運動的總時間和運動方式,如:
{
‘times’ : 1000,//運動總時間為1s
‘fx’ : ‘linear’ // 運動形式為勻速
}
當options傳入引數為空json{}時,就使用預設設定(運動時間500ms,運動形式為勻速)
引數endFn(可選) : 結束運動後要執行的方法
//基於事件的運動框架用法
window.onload=function(){
//得到你要運動的元素
var oDiv = document.getElementsByTagName('div')[0];
//使用運動框架
var mover = new Mover();
oDiv.onclick=function(){
mover.startMoveByTime(
this,
{'left':500,'top':200},
{'times':1000,'fx':'easeIn'},
function(){
mover.startMoveByTime(this,{'opacity':20},{});
});
//使oDiv的left變為500px,高度變為200px,結束上述運動後再使透明度變為20%
}
}
現在來說說兩種方式的區別吧,使用第一種方式進行運動時,元素的各項需要改變的屬性的運動速度相同,而由於每項屬性起點到終點的距離不一樣,所以各項屬性到達運動終點的時間也不一樣。而第二種運動直接固定了運動總時間相同,所以所有傳入引數的屬性一起改變、一起終止。
以下是Mover.js元件的程式碼,筆者乃菜鳥一隻,歡迎指正,後面有時間也會將彈性運動、碰撞運動、重力運動一起寫入框架
/*
js原生運動元件
*/
//Mover建構函式
function Mover(){
this.setting = {
'times' : 500,
'fx' : 'linear'
}
}
//獲取當前樣式
Mover.prototype.getStyle = function(obj,attr)
{
return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj)[attr];
}
//獲取當前時間
Mover.prototype.now = function(){
return (new Date()).getTime();
}
//速度版運動框架
Mover.prototype.startMoveBySpeed = function (obj,json,fnEnd)
{
clearInterval(obj.timer);
_this = this;
obj.timer = setInterval(function(){
obj.bStop = true;
for(var attr in json)
{
var cur = 0;
var speed = 0;
if(attr === 'opacity')
{
cur = _this.getStyle(obj,attr);
cur = Math.round( parseFloat(cur*100) );
}
else
{
cur = parseInt(_this.getStyle(obj,attr));
}
var speed = (json[attr]-cur)/8;
speed = speed ? Math.ceil(speed):Math.floor(speed);
if(cur !== json[attr])
{
obj.bStop = false;
}
if(attr === 'opacity')
{
obj.style.opacity = (cur+speed)/100;
obj.style.filter = 'Alpha(opacity:'+(cur+speed)+')';
}
else
{
obj.style[attr] = (cur+speed)+'px';
}
}
if(obj.bStop)
{
clearInterval(obj.timer);
fnEnd && fnEnd.call(obj);
}
},20);
}
//時間版運動框架
Mover.prototype.startMoveByTime = function(obj,json,options,endFn){
//對於時間版框架來說,初始值b是固定的,所以寫在定時器外面
var _this = this;
//預設設定
extend(_this.setting,options);
var iCur = {};
//獲取當前值
for(attr in json)
{
iCur[attr] = 0;
if(attr === 'opacity')
{
iCur[attr] = Math.round( parseFloat( _this.getStyle(obj,attr) )*100 );
}else{
iCur[attr] = parseInt( _this.getStyle(obj,attr) );
}
};
var iStartTime = _this.now();
clearInterval(obj.timer);
obj.timer = setInterval(function(){
var iCurTime = _this.now();
var t = _this.setting.times-
Math.max(0,iStartTime-iCurTime+_this.setting.times);
for(attr in json)
{
/*
Tween[fx]函式4個引數
t:current time(當前時間)
b:beginning value(初始值)
c: change in value(變化量)
d:duration(持續時間)
return (目標點)
*/
var value = _this.Tween[_this.setting.fx](
t, //t 0~times
iCur[attr], //b
json[attr]-iCur[attr], //c
_this.setting.times //d
);
if(attr === 'opacity')
{
obj.style[attr] = parseFloat(value/100);
obj.style.filter = 'alpha(opacity:'+value+')';
}else{
obj.style[attr] = value + 'px';
}
}
if( t === _this.setting.times )
{
clearInterval(obj.timer);
endFn && endFn.call(obj);
}
},13);
}
//覆蓋預設設定
function extend(child,father){
for(var attr in father)
{
child[attr] = father[attr];
}
}
//Tween運動演算法
Mover.prototype.Tween = {
/*
4個引數
t:current time(當前時間)
b:beginning value(初始值)
c: change in value(變化量)
d:duration(持續時間)
return (目標點)
*/
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;
}
}