构造自己的动画函数:animation,stop功能的实现

时间:2023-03-09 17:07:31
构造自己的动画函数:animation,stop功能的实现

最近做一个广告项目,里面涉及很多动画效果,由于不能使用jquery,所以只能构建自己的动画方法。

数据结构:

elem是DOM对象,给它设置一个属性对象,用来记录elem的动画对象,比如'left','opacity'等。该对象的属性又有自己的动画队列,队列的每一项是一个对象,该对象有两个属性start,end,分别用来存储开始的值和动画结束的值,该对象有三个方法,begin,finish是开始结束动画,callbak用来保存该动画结束时需要执行的函数,见下图:

构造自己的动画函数:animation,stop功能的实现

animation方法:

分词器,用来解析value表达式,比如:"+=300px"

function expr(key,value){
var r=/^(?:(\+|-)=)?(-?\d+(?:\.\d+)?)(px|)$/;
var matches=r.exec(value);
if(!matches){
throw new Error("传入参数不能运行动画");
}else{
return {
"operator":matches[1]?matches[1]:"",
"num":matches[2]?matches[2]:"",
"unit":matches[3]?matches[3]:""
};
}
}

调用上边这个方法:

var matchesEnd=expr(key,value);

就得到一个分词结果对象:

{
"operator":"+",
"num":300,
"unit":"px"
} begin方法中,我们需要先获取动画前的样式,代码如下:
var curValue=_.getAppliedStyle(elem,key);//获取当前样式
if((curValue==="auto")&&(revise[key]===0)){////修正top right bottom left width height 默认值为auto的情况
value=0;
}
temp.start=curValue;
var matchesStart=expr(key,curValue);//设置动画初始值

代码:

动画模块:

(function(window){
function expr(key,value){
var r=/^(?:(\+|-)=)?(-?\d+(?:\.\d+)?)(px|)$/;
var matches=r.exec(value);
if(!matches){
throw new Error("传入参数不能运行动画");
}else{
return {
"operator":matches[1]?matches[1]:"",
"num":matches[2]?matches[2]:"",
"unit":matches[3]?matches[3]:""
};
}
}
//method of animation
//@elem
//@properties example:{"left":"1000px",top:"200px"} opacity请使用w3c标准:0-1
//@options example:{speed:200}
function animation(elem,properties,options,callback){
var speed=options.speed||1000;
var inter=20;
if(navigator.userAgent.indexOf("MSIE 8.0")>0){
inter=80;
}
if(!elem.ani){
elem.ani={};
}
_.each(properties,function(value,key){
if(!elem.ani[key]){
elem.ani[key]=[];
}
var matchesEnd=expr(key,value);
var temp={};
if(!matchesEnd.operator){
temp.end=value;
}
var st;
if(matchesEnd.num){
var i=0;
temp.callback=callback;
temp.begin=function(){
var curValue=_.getAppliedStyle(elem,key);
temp.start=curValue;
var matchesStart=expr(key,curValue);
if(matchesEnd.operator){
temp.end=matchesStart.num*1+(matchesEnd.operator==="+"?1*matchesEnd.num:(-1)*matchesEnd.num)+matchesEnd.unit;
matchesEnd=expr(key,temp.end);
}
var gap=matchesEnd.num-matchesStart.num;
var step=gap/speed*inter;
var num=gap/step;
st=setInterval(function(){
i++;
var tempValue=matchesStart.num*1+step*i+matchesEnd.unit;
_.setStyle(elem,key,tempValue);
if(i>=num){
//修正可能的计算错误
_.setStyle(elem,key,temp.end);
if(callback){
temp.callback.call(temp);
}
clearInterval(st);
elem.ani[key].shift();
if(elem.ani[key].length){
elem.ani[key][0].begin();
}
}
},inter);
};
temp.finish=function(){
if(st){
clearInterval(st);
}
} if(elem.ani[key].push(temp)===1){
temp.begin();
}
}
},this);
}
function stop(elem,callback){
for(var key in elem.ani){
var len=elem.ani[key].length;
if(len){
elem.ani[key][0].finish();
if(elem.ani[key][0].callback){
elem.ani[key][0].callback.call(this);
}
_.setStyle(elem,key,elem.ani[key][len-1].end);
elem.ani[key].length=0;
if(callback){
callback();
}
}
}
}
window.AniModule={};
window.AniModule.animation=animation;
window.AniModule.stop=stop;
})(window);

工具函数:

(function(){
var root=this;
root._={};
var breaker={};
var ArrayProto=Array.prototype,
ObjProto=Object.prototype,
FuncProto=Function.prototype; var hasOwnProperty=ObjProto.hasOwnProperty; //ECMAScript 5 native function
var nativeForEach=ArrayProto.forEach,
nativeKeys=Object.keys;

_.isIE=!-[1,];
_.keys=nativeKeys||function(obj){
if(obj!==Object(obj)) throw new TypeError('Invalid object');
var keys=[];
for(var key in obj){
if(hasOwnProperty.call(obj,key)){
keys.push(key);
}
}
return keys;
}; _.each=function(obj,iterator,context){
if(obj==null) return;
if(nativeForEach&&obj.forEach===nativeForEach){
obj.forEach(iterator,context);
}else if(obj.length===+obj.length){
for (var i = 0,length=obj.length; i < length; i++) {
if(iterator.call(context,obj[i],i,obj)===breaker) return;
}
}else{
var keys=_.keys(obj);
for(var i=0,length=keys.length;i<length;i++){
if(iterator.call(context,obj[keys[i]],keys[i],obj)===breaker) return;
}
}
}; _.getAppliedStyle=function(elem,styleName){
var style="";
if(styleName== "opacity"&&_.isIE){
style=elem.filters('alpha').opacity/100;
}else if(window.getComputedStyle){
style=elem.ownerDocument.defaultView.getComputedStyle(elem,null).getPropertyValue(toHyphens(styleName));
}else if(elem.currentStyle){
style=elem.currentStyle[toCamelCase(styleName)];
}
function toHyphens(camelCaseValue){
var result=camelCaseValue.replace(/[A-Z]/g,function(c){
return ("-"+c.charAt(0).toLowerCase());
});
return result;
}
function toCamelCase(hyphenatedValue){
var result=hyphenatedValue.replace(/-\D/g,function(c){
return c.charAt(1).toUpperCase();
});
return result;
}
return style;
}; _.setStyle=function(elem,name,value){
if(name=="opacity"&&_.isIE){
elem.style["filter"]="alpha(opacity="+value*100+")";
}else{
elem["style"][name]!==undefined?elem["style"][name]=value:elem[name] = value;
}
};
}).call(this);

调用:animation方法:

window.AniModule.animation(elem,{"left":"+=300px"},{"speed":1000});

stop方法:

window.AniModule.stop(elem);