|
javascript 小型动画组件与实现代码,想要学习js动画的朋友可以参考下。思路确实很实用。
做一个普通的动画效果,js是怎么完成的呢.看一下例子 复制代码 代码如下: setInterval(function(){ element.style.left =parseFloat(element.style.left) +(n) +'px'; },10);
[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行] 用window.setInterval 动画函数 ,每隔10毫秒 都会去执行一次动画 ; 和 set配套的是 clearInterval 函数,用来结束动画。 每隔setInterval 都会返回一个类似于线程id的值 ; var interval =setInterval(function(){ element.style.left =parseFloat(element.style.left) +(n) +'px'; },10); 用 clearInterval (interval) 既可结束动画播放. interval = setInterval(function(){ if(parseFloat(element.style.left)>500) clearInterval(interval) element.style.left =parseFloat(element.style.left) +2 +'px'; },10); 超过500px的时候,动画就会停止, element将不在移动。
[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行] 但是上面的动画是比较生硬的,然后我们有另外一种时间线动画。 看例子: var element = document.getElementById('test1'); var start = +new Date,dur=1000,finish = start+dur; interval = setInterval(function(){ var time = +new Date, pos = time > finish ? 1 : (time-start)/dur; element.style.left = (100*pos)+"px"; if(time>finish) { clearInterval(interval); } },10); start 为目标动画的开始时间 ( +new Date 其实就是 new Date().getTime() ) dur 为 动画执行一共所需要的时间 finish 是目标动画结束的时间 pos = time > finish ? 1 : (time-start)/dur; //可以把pos 想象成频率 ,一个时间比 (100*pos) ,100代表距离,,如果距离为500px 就设置为 500*pos; time>finish : 如果超过时间,就停止动画!
[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行] 很好,到这里我们已经知道一个简单动画效果是怎么样写的了. 再来看一个小型的完整的动画组件是如何写的 : 复制代码 代码如下: (function($,name){ var parseEl = document.createElement('div') , props = ('backgroundColor borderBottomColor borderBottomWidth borderLeftColor borderLeftWidth '+ 'borderRightColor borderRightWidth borderSpacing borderTopColor borderTopWidth bottom color fontSize '+ 'fontWeight height left letterSpacing lineHeight marginBottom marginLeft marginRight marginTop maxHeight '+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset outlineWidth paddingBottom paddingLeft '+ 'paddingRight paddingTop right textIndent top width wordSpacing zIndex').split(' ') , normalize =function (style){ var css, rules = {}, i = props.length, v; parseEl.innerHTML = '<div style="'+style+'"></div>'; css = parseEl.childNodes[0].style; while(i--) if(v = css[props[i]]) rules[props[i]] = parse(v); return rules; }, color = function(source,target,pos){ var i = 2, j, c, tmp, v = [], r = []; while(j=3,c=arguments[i-1],i--) if(s(c,0)=='r') { c = c.match(/\d+/g); while(j--) v.push(~~c[j]); } else { if(c.length==4) c='#'+s(c,1)+s(c,1)+s(c,2)+s(c,2)+s(c,3)+s(c,3); while(j--) v.push(parseInt(s(c,1+j*2,2), 16)); } while(j--) { tmp = ~~(v[j+3]+(v[j]-v[j+3])*pos); r.push(tmp<0?0:tmp>255?255:tmp); } return 'rgb('+r.join(',')+')'; }, parse = function(prop){ var p = parseFloat(prop), q = prop.replace(/^[\-\d\.]+/,''); return isNaN(p) ? { v: q, f: color, u: ''} : { v: p, f: interpolate, u: q }; }, s = function(str, p, c){ return str.substr(p,c||1);//color 用 }, interpolate =function(source,target,pos){ return (source+(target-source)*pos).toFixed(3); }, flower = function(el, style,opts,after){ var el = document.getElementById(el), //通过id获取元素对象 opts = opts || {}, target = normalize(style), comp = el.currentStyle ? el.currentStyle : getComputedStyle(el, null), //ie和w3c兼容,获取样式 prop, current = {}, start = +new Date, //开始时间 dur = opts.duration||200, //执行事件,默认为200 finish = start+dur, //结束时间 interval, easing = opts.easing || function(pos){ return (-Math.cos(pos*Math.PI)/2) + 0.5; }; for(prop in target) current[prop] = parse(comp[prop]); interval = setInterval(function(){ var time = +new Date, pos = time>finish ? 1 : (time-start)/dur; for(prop in target){ el.style[prop] = target[prop].f(current[prop].v,target[prop].v,easing(pos)) + target[prop].u; } if(time>finish) { clearInterval(interval); opts.after && opts.after(); after && setTimeout(after,1); } },10); }; $[name] = flower; })(window,"flower"); 复制代码 代码如下: var parse = function(prop){ var p = parseFloat(prop), q = prop.replace(/^[\-\d\.]+/,''); return isNaN(p) ? { v: q, f: color, u: ''} : { v: p, f: interpolate, u: q }; } var p = parseFloat(prop) 意思是 : 500px => 500; q = prop.replace(/^[\-\d\.]+/,''); 500px => px; return isNaN(p) ? { v: q, f: color, u: ''} : { v: p, f: interpolate, u: q }; 意思是 如果取的是颜色值(因为带有#号),返回{ v: q, f: color, u: ''} u 代表代为,f是一个color函数(后面会讲到); var s = function(str, p, c){ return str.substr(p,c||1); } s 函数是用来截取字符串,并将最后结果返回 color 函数 将颜色值,最后统一返回 "rgb(x,x,x)" 的形式 normalize 函数 返回一个json对象,对象里包含了该元素要执行的css属性名和值 while(i--) if(v = css[props[i]]) rules[props[i]] = parse(v); 把一行代码拆开,看看到底如何作用 while(i--){ //这里用了一个 =号, 先进行赋值运算,如果不存在之 if将不通过, 一举两得 : ) if(v = css[props[i]]){ rules[props[i]] = parse(v); //赋给新的对象, } } interpolate函数中 return (source+(target-source)*pos).toFixed(3); toFixed 是为了解决小数问题,如 0.000000001; 会变成 1e-9; 不是我们想要的结果,通过toFixed 可以解决, toFixed (n), 其中n代表保留小数点后几位 el.currentStyle ? el.currentStyle : getComputedStyle(el, null); 这个其实兼容多浏览器,获取元素的一句代码 具体参考 : JS 获取最终样式 【getStyle】 flower的 4个参数 el 目标对象,style 是最终样式,opts,是参数选项包括 (dur时间,easing缓懂函数,after结束后运行的callbak) ,第4个after是最后执行的callbak; opts.easing 可以利用各种缓动算法,来改变元素的运动状态; 如 复制代码 代码如下: function bounce(pos) { if (pos < (1/2.75)) { return (7.5625*pos*pos); } else if (pos < (2/2.75)) { return (7.5625*(pos-=(1.5/2.75))*pos + .75); } else if (pos < (2.5/2.75)) { return (7.5625*(pos-=(2.25/2.75))*pos + .9375); } else { return (7.5625*(pos-=(2.625/2.75))*pos + .984375); } } (function($,name){ window.flower = flower; })(window,'flower'); 这样其实就是让内部函数自由,并且只通过这个调用去暴露一个接口。不然外面的函数,访问不到匿名函授中的flower; 看一下调用的例子 : ) 复制代码 代码如下: <div id="test1" style="position:absolute;left:0px;background:#f00;opacity:0">test</div> <div id="test2" style="border:0px solid #00ff00;position:absolute;left:0px;top:400px;background:#0f0">test</div> <script> (function($,name){ var parseEl = document.createElement('div') , props = ('backgroundColor borderBottomColor borderBottomWidth borderLeftColor borderLeftWidth '+ 'borderRightColor borderRightWidth borderSpacing borderTopColor borderTopWidth bottom color fontSize '+ 'fontWeight height left letterSpacing lineHeight marginBottom marginLeft marginRight marginTop maxHeight '+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset outlineWidth paddingBottom paddingLeft '+ 'paddingRight paddingTop right textIndent top width wordSpacing zIndex').split(' ') , normalize =function (style){ var css, rules = {}, i = props.length, v; parseEl.innerHTML = '<div style="'+style+'"></div>'; css = parseEl.childNodes[0].style; while(i--) if(v = css[props[i]]) rules[props[i]] = parse(v); return rules; }, color = function(source,target,pos){ var i = 2, j, c, tmp, v = [], r = []; while(j=3,c=arguments[i-1],i--) if(s(c,0)=='r') { c = c.match(/\d+/g); while(j--) v.push(~~c[j]); } else { if(c.length==4) c='#'+s(c,1)+s(c,1)+s(c,2)+s(c,2)+s(c,3)+s(c,3); while(j--) v.push(parseInt(s(c,1+j*2,2), 16)); } while(j--) { tmp = ~~(v[j+3]+(v[j]-v[j+3])*pos); r.push(tmp<0?0:tmp>255?255:tmp); } return 'rgb('+r.join(',')+')'; }, parse = function(prop){ var p = parseFloat(prop), q = prop.replace(/^[\-\d\.]+/,''); return isNaN(p) ? { v: q, f: color, u: ''} : { v: p, f: interpolate, u: q }; }, s = function(str, p, c){ return str.substr(p,c||1); }, interpolate =function(source,target,pos){ return (source+(target-source)*pos).toFixed(3); }, flower = function(el, style,opts,after){ var el = document.getElementById(el), opts = opts || {}, target = normalize(style), comp = el.currentStyle ? el.currentStyle : getComputedStyle(el, null), prop, current = {}, start = +new Date, dur = opts.duration||200, finish = start+dur, interval, easing = opts.easing || function(pos){ return (-Math.cos(pos*Math.PI)/2) + 0.5; }; for(prop in target) current[prop] = parse(comp[prop]); interval = setInterval(function(){ var time = +new Date, pos = time>finish ? 1 : (time-start)/dur; for(prop in target){ el.style[prop] = target[prop].f(current[prop].v,target[prop].v,easing(pos)) + target[prop].u; } if(time>finish) { clearInterval(interval); opts.after && opts.after(); after && setTimeout(after,1); } },10); }; $[name] = flower; })(window,"flower"); (function(){ var bounce = function(pos) { if (pos < (1/2.75)) { return (7.5625*pos*pos); } else if (pos < (2/2.75)) { return (7.5625*(pos-=(1.5/2.75))*pos + .75); } else if (pos < (2.5/2.75)) { return (7.5625*(pos-=(2.25/2.75))*pos + .9375); } else { return (7.5625*(pos-=(2.625/2.75))*pos + .984375); } } flower('test2', 'left:300px;padding:10px;border:50px solid #ff0000', { duration: 1500, after: function(){ flower('test1', 'background:#0f0;left:100px;padding-bottom:100px;opacity:1', { duration: 1234, easing: bounce }); } }); })(); </script> 参考 : http://scripty2.com/doc/scripty2%20fx/s2/fx/transitions.html |
|