您的位置:首页 > Web前端 > JavaScript

javascript流畅动画效果,包括颜色,style属性,dom元素属性一步搞定

2009-11-07 15:52 711 查看
javascript的动画效果一般体现在HTMLElement元素的3个属性上:

style对象的属性,如height,width,marginLeft等等

由于颜色的拐藻形式,如#eee,#ffffff,rgb(0,0,0)还有名字还百分比的我都不想提了,所以算然颜色也是style的属性但单独领出来。又称颜色梯度渐变。

就是HTMLElement的一些view properties,如scrollTop.当然有些是可以赋值的有些是只读的

自定义动画无非就是用定时器来改变上面提到的属性了,我们也分3步走:

解析自定义动画参数

配置动画步骤

启动定时器开始动画

如何能让低效率的javascript流畅动画呢见这里 : http://blog.csdn.net/tom_221x/archive/2009/09/07/4528564.aspx
现在无废话见代码:

第一部解析动画参数

/**
* 参数格式
* anim({需要动画的属性},动画时间,回调参数,缓冲算法,缓冲效果)
* anim({需要动画的属性},{dur:动画时间,fn:回调参数,type:缓冲算法,ease:缓冲效果})
*/
anim : function(){//自定义动画
var args = arguments,obj = args[0],//obj为需要动画的属性
dur,fn,type,ease,//动画时间,回调参数,缓冲算法,缓冲效果
ops,arr,p,//辅助变量
ems,//这个为需要动画的HTMLElement的数组,想法传给它
tids = [];//存放计时器id

///凡是有"||"的都是可选,提供了默认值
if(args.length == 2 && typeof args[1] == "object"){//参数为对象的形式
ops = args[1];
dur = ops.dur || 300;//动画时间
fn = ops.fn || null;//完成回调函数
type = ops.type || "swing";//动画类型
ease = ops.ease || "easeIn";//缓冲类型
}else{//多参数形式
dur = args[1] || 300;
fn =  args[2] || null;
type =  args[3] || "swing";
ease =  args[4] || "easeIn";
}

ops = [];//依次装入:属性名,符号,值,单位
for(p in obj){//解析属性值
ops.push(p);
if (p.toLowerCase().indexOf("color") != -1) {//颜色属性
ops.push(obj[p]);
ops.push("#");
ops.push("");
}else {
arr = obj[p].match(/((-=)?|(/+=)?)(-?/d+)(/D*)/);
ops.push(arr[2] || arr[3]);
ops.push(arr[4]);
ops.push(arr[5] || "px");//动画属性没有单位默认值
}
}
arr = this;//传递给回调函数作为this的值
for (var i = 0, j = ems.length; i < j; i++){
tids.push(jo.parseAnim(ems[i],ops,dur,type,ease,fn,arr));
}

}


这一步之后ops这个数组中存放了我们需要动画的属性,例如{height:'300px',width:'+=300px',color:'#eee'},

ops = ['height','',300,'px','width','+=','px','color','#eee','#','']可以看到每4个位置存放一个动画属性

接下来第二部配置动画步骤:

//e表示要动画的HTMLElement的元素
parseAnim : function(e,ops,dur,type,ease,fn,ths){//配置anim
var	len = ops.length,
step = [],//属性值数组
isColor;//是否为颜色属性
for (var i = 0; i < len; i += 4) {
isColor = ops[i + 2] == "#";
if (!isColor) {//不是颜色属性
var b ,c;//初始值,变化值
if(typeof e[ops[i]] == "undefined"){
b = parseInt(this.getStyle(ops[i], e));//这个getStyle后面附上
if (isNaN(b)) {//设置初始值
b = 0;
}
} else {
b = e[ops[i]];
}

switch (ops[i + 1]) {//判断符号,设置变化量
case "+=":
c = ops[i + 2] * 1;
break;
case "-=":
c = ops[i + 2] * 1 - ops[i + 2] * 2;
break;
default:
c = ops[i + 2] * 1 - b;
}
step.push(b);//压入当前属性的初始值
step.push(c);//压入当前属性的变化值
}else {//颜色属性
var arr = [],//RGB三种颜色的初始值(b1,b2,b3)和变化值(c1,c2,c3)
rgb1 = this.color10(this.getStyle(ops[i], e)),//十进制RGB初始颜色
rgb2 = this.color10(ops[i + 1]);//十进制RGB最终颜色
for(var n = 0;n < 3;n++){
arr
= rgb1
* 1;
arr[n + 3] = rgb2
* 1 - arr
;
}

step.push(arr);//压入颜色属性的变化数组
step.push("#");//表示为颜色数组
}

step.push(0);//当前属性的动画开始时间
step.push(ops[i]);//压入当前属性的属性名
step.push(ops[i + 3]);//当前属性单位
}
return this.timer(step,fn,e,ths,dur,type,ease);
}


这里主要是计算动画的初始值和最终值,并且判断相对运动方向,如+=,-+,用到了两个辅助函数,如下

//获得当前元素的动画属性的样式
getStyle : function(sty,e){//获取style
var obj =  e.currentStyle || window.getComputedStyle(e, null);
switch (sty) {
case "float" : return  obj.styleFloat || obj.cssFloat;
case "opacity" : return e.filters ? (e.filters.alpha ? e.filters.alpha.opacity : 100) : obj.opacity * 100;
default : return obj[sty];
}
}


color10 : function(cor){//转换颜色为十进制值
var rgb = [],len = cor.length;
if(len == 7){//#000000格式
for(var i = 0;i < 3;i++){
rgb[i] = parseInt(cor.substring(2 * i + 1,2 * i + 3),16);
}
}else if(len == 4){//#000格式
cor = cor.replace(//w{1}/g,"$&$&");
for(var i = 0;i < 3;i++){
rgb[i] = parseInt(cor.substring(2 * i + 1,2 * i + 3),16);
}
}else{//rgb(0,0,0)格式
if (cor == "transparent") {//这里应该是取得父类元素的背景颜色,如果为透明继续递归,直到body,这样比较合理
cor = "rgb(255,255,255)";
}
rgb = cor.match(//d+/g).toString().split(",");
}
return rgb;
}


着这步之后step数组中存放了,需要动画的属性,开始值与最终值,例如{height:'300px',width:'+=300px',color:'#eee'}

step = [

height的初始值,300,0(这个是动画开始时间,后面用到),'height','px',

width的初始值,计算后的width的值,0,'width','px',

十进制颜色数组,'#'(表示为颜色属性),0,'color',''

]

可以看到,每5个位置存放一个动画属性的相关信息,现在一切就绪了需要启动计时器开始动画了

timer : function(step,fn,e,ths,dur,type,ease){
var j = step.length,k = j/5,
end,start = new Date().valueOf(),
tid = setInterval(function(){
//计算每次间隔时间所花费的时间,在tween算法中需要,也是屏蔽了浏览器执行效率的差异
//因为setInterval设置10,浏览器的运行时间是不止10的
end = new Date().valueOf();
var step2,step3,step1,stepi;
for(var i = 0;i < j; i += 5){
step2 = step[i + 2];
if (step2 != dur) {//当前属性动画未完成
step[i + 2] = step2 += end - start;
if(step2 > dur){//当前属性动画完成
step[i + 2] = step2 = dur;
}
step3 = step[i + 3];
step1 = step[i + 1];
stepi = step[i];
if (step1 == "#") {//颜色属性
for(var n = 0,m;n < 3;n++){
//调用了动画算法.后面附上
m = Math.ceil(tween[type][ease](step2, stepi
, stepi[n + 3], dur)).toString(16);
stepi[n + 6] = m.length == 1 ? "0" + m : m;
}
jo.setStyle(step3, e, "#" + stepi[6] + stepi[7] + stepi[8]);
}else {//非颜色属性
if (typeof e[step3] == "undefined") {
//setStyle后面附上
jo.setStyle(step3, e, Math.ceil(tween[type][ease](step2, stepi, step1, dur)) + step[i + 4]);
} else {
//调用了动画算法.后面附上
//这里是处理诸如scrollTop这样的属性的,也就是说这个动画函数可以渐变HTMLElement元素的任何数值属性
e[step3] = Math.ceil(tween[type][ease](step2, stepi, step1, dur));
}
}
}else{
k--;//未完成属性动画计数器
}
}

if (k != 0) {
start = end;
}else {//所有属性动画完成
clearInterval(tid);
var tids = ths.tids;
for (var w = 0, z = tids.length; w < z; w++) {
if (tids[w] == tid) {
tids.splice(w, 1);
}
}
if (fn) {
fn.call(ths, e);
}
}
},10);
return tid;
}


下面是tween算法和辅助函数

/*
补间缓冲动画算法
t: current time 当前时间
b: beginning value 初始值
c: change in value 变化量
d: duration 持续时间
每个效果都分三个缓动方式:
easeIn:从0开始加速的缓动;
easeOut:减速到0的缓动;
easeInOut:前半段从0开始加速,后半段减速到0的缓动。
*/
tween = {
swing: {//这个就是jquery的默认算法,当然有更多,也可以自己设计,google吧
easeIn: function(t, b, c, d){
return ((-Math.cos(t / d * Math.PI) / 2) + 0.5) * c + b;
}
}
};


setStyle : function(sty, e, val){
var obj = e.style;
switch (sty) {
case "float" : obj.styleFloat ? obj.styleFloat = val : obj.cssFloat = val;
break;
case "opacity" : e.filters ? obj.filter = (e.currentStyle.filter || "").replace(/alpha/([^)]*/)/, "") + "alpha(opacity="+val+")" : obj.opacity = val / 100;
break;
default : obj[sty] = val;
}
}


最后可运行代码下载和示例见这里:

http://mojo-js.appspot.com/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: