jQuery 的动画为了稳定与兼容的的选择,所以即使在目前的 2.1.1 的版本中也是采用的帧动画而不是最新的 CSS3 动画,至于原因当然有很多我们这里就只涉及框架的帧动画的处理,帧动画的实现动画的原理跟动画片的制作一样。动画片是把一些差距不大的原画以一定帧数播放, js 动画是靠连续改变元素的某个 css 属性值,比如 left, top 达到视觉的动画效果。
book.animate({ left: '+=50', }).animate({ left: '+=100', }).animate({ left: '-=50', });
这里是一组最简单的动画,但是在设计上会有一个最重要的问题:
因为动画是异步的,但是 animate 方法的链式代码是同步的,所以这里要涉及一个最重要的问题,动画队列要如何有序的调用?
传统的思路
jQuery 为动画量身定制了队列机制,我们的思路可以是这样
总结
两方方法都是利用异步收集同步的代码,区别就是一个是靠定时器,一个是靠动画自身,所以在精确度上来说显然是动画自身控制是最合理的。好比我们去面试,面试官只要让每一个面试完毕的人去通知后面的人继续进来面试一样,如此反复
右边代码,请在支持 webkit 的浏览器下面调试,谷歌、急速360。
<!doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"/> <title>动画思路</title> </head> <body> 请在支持webkit的浏览器下面调试,谷歌、急速360 <div id="div1" style="width:100px;height:50px;background:red;cursor:pointer;color:#fff;text-align:center;line-height:50px;">点击执行动画</div> <script type="text/javascript"> (function($) { window.$ = $; })(function() { var rquickExpr = /^(?:#([\w-]*))$/; function aQuery(selector) { return new aQuery.fn.init(selector); } /** * 动画 * @return {[type]} [description] */ var animation = function() { var self = {}; var Queue = []; //动画队列 var fireing = false //动画锁 var first = true; //通过add接口触发 var getStyle = function(obj, attr) { return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj, false)[attr]; } var makeAnim = function(element, options, func) { var width = options.width //包装了具体的执行算法 //css3 //setTimeout element.style.webkitTransitionDuration = '2000ms'; element.style.webkitTransform = 'translate3d(' + width + 'px,0,0)'; //监听动画完结 element.addEventListener('webkitTransitionEnd', function() { func() }); } var _fire = function() { //加入动画正在触发 if (!fireing) { var onceRun = Queue.shift(); if (onceRun) { fireing = true; //next onceRun(function() { fireing = false; _fire(); }); } else { fireing = true; } } } return self = { //增加队列 add: function(element, options) { Queue.push(function(func) { makeAnim(element, options, func); }); //如果有一个队列立刻触发动画 if (first && Queue.length) { first = false; self.fire(); } }, //触发 fire: function() { _fire(); } } }(); aQuery.fn = aQuery.prototype = { run: function(options) { animation.add(this.element, options); return this; } } var init = aQuery.fn.init = function(selector) { var match = rquickExpr.exec(selector); var element = document.getElementById(match[1]) this.element = element; return this; } init.prototype = aQuery.fn; return aQuery; }()); //dom var oDiv = document.getElementById('div1'); //调用 oDiv.onclick = function() { $('#div1').run({ 'width': '500' }).run({ 'width': '300' }).run({ 'width': '1000' }); }; </script> </body> </html>