内容简介:前言:需要先看
前言:
需要先看 jQuery源码解析之 $
.queue()、 $
.dequeue()和jQuery.Callbacks()
一、举例
divA
的宽度先变成 500px,再变成 300px,最后变成 1000px:
<script src="jQuery.js"></script> <div id="A" style="width:100px;height:50px;background-color: deeppink">这是A</div> <script> let A = document.querySelector('#A'); //在异步调用中,进行同步调用 //动画是异步的 A.onclick = function() { //就是连续调用animation.add() $('#A').animate({ 'width': '500' }).animate({ 'width': '300' }).animate({ 'width': '1000' }); }; </script>
二、 $
().animate()
作用:
通过 CSS 样式将元素从一个状态改变为另一个状态
源码:
//之前有说过: jQuery.fn.extend() 是$()的方法 jQuery.fn.extend( { //源码8062行 //{'width': '500'} animate: function( prop, speed, easing, callback ) { //是否是空对象,false var empty = jQuery.isEmptyObject( prop ), // optall={ // complete:function(){jQuery.dequeue()}, // old:false, // duration: 400, // easing: undefined, // queue:"fx", // } //undefined undefined undefined optall = jQuery.speed( speed, easing, callback ), doAnimation = function() { // Operate on a copy of prop so per-property easing won't be lost //Animation 方法执行单个动画的封装 //doAnimation的本质是执行Animation方法 //this:目标元素 //{'width': '500'} //optall={xxx} var anim = Animation( this, jQuery.extend( {}, prop ), optall ); // Empty animations, or finishing resolves immediately //finish是数据缓存的一个全局变量 //如果为true,立即终止动画 if ( empty || dataPriv.get( this, "finish" ) ) { anim.stop( true ); } }; //注意这个 //自身的.finish=自身 doAnimation.finish = doAnimation; return empty || optall.queue === false ? this.each( doAnimation ) : //一般走这里 //通过 queue 调度动画之间的衔接 //optall.queue:"fx" //doAnimation:function(){} this.queue( optall.queue, doAnimation ); }, })
解析:
(1)jQuery.speed()
作用:
初始化动画对象的属性
源码:
//源码8009行 //undefiend undefined undefined //作用是返回一个经过修改的opt对象 jQuery.speed = function( speed, easing, fn ) { // opt={ // complete:false, // duration: undefined, // easing: undefined, // } var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { complete: fn || !fn && easing || isFunction( speed ) && speed, duration: speed, easing: fn && easing || easing && !isFunction( easing ) && easing }; // Go to the end state if fx are off /*这边是为opt.duration赋值的*/ //undefiend if ( jQuery.fx.off ) { opt.duration = 0; } else { if ( typeof opt.duration !== "number" ) { if ( opt.duration in jQuery.fx.speeds ) { opt.duration = jQuery.fx.speeds[ opt.duration ]; } else { //走这边 //_default=400 opt.duration = jQuery.fx.speeds._default; } } } /*为opt.queue赋值*/ // Normalize opt.queue - true/undefined/null -> "fx" //注意这个==,是模糊判断 if ( opt.queue == null || opt.queue === true ) { opt.queue = "fx"; } // Queueing /*为opt.old赋值*/ opt.old = opt.complete; opt.complete = function() { if ( isFunction( opt.old ) ) { opt.old.call( this ); } //如果queue有值得话,就出队列 //因为queue默认为"fx",所以一般会触发dequeue操作 if ( opt.queue ) { //this指目标元素 //opt.queue jQuery.dequeue( this, opt.queue ); } }; //此时的opt为: // opt={ // complete:function(){jQuery.dequeue()}, // old:false, // duration: 400, // easing: undefined, // queue:"fx", // } return opt; };
解析:
通过传入的三个参数,对 opt
对象进行处理,如果三个参数都为 undefined
的话, opt
等于:
opt={ complete:function(){jQuery.dequeue()}, old:false, duration: 400, easing: undefined, queue:"fx", }
(2) animate
内部做了什么?
作用:
animate
内部封装了一个 doAnimation
触发器,触发器触发就会运行 Animation
方法, animate
最后返回的是 queue()
方法,注意 queue()
方法的参数带有触发器 doAnimation
(3) $().queue()
作用:
执行入队操作( jQuery.queue()
),如果是fx动画的话,同时执行出队操作( jQuery.dequeue()
)
源码
这个方法上篇文章已经分析过了,这里就简单分析下:
jQuery.fn.extend( { //optall.queue:"fx" //doAnimation:function(){} //fx动画的话,就执行dequeue(),也就是队首callback函数 queue: function( type, data ) { //返回的是数组[doAnimate,doAnimate,xxx] var queue = jQuery.queue( this, type, data ); //初始化hooks jQuery._queueHooks( this, type ); /*专门为fx动画做处理*/ //如果队首没有锁的话,直接运行队首元素 if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { jQuery.dequeue( this, type ); } },
解析:
inprogress
是动画队列的锁,目的是 保证上个动画执行结束后,再去执行下个动画
每入队一个 doAnimate
函数,如果队首没有 inprogress
锁的话,就会出队去运行一个 doAnimate
函数
jQuery._queueHooks()
的意义在于添加一个 empty.remove()
方法,用来清空队列 queue
(4) jQuery.queue()
作用:
上篇文章也分析过了,就是将 doAnimate
函数 push
进 queue
数组中
(5) jQuery.dequeue()
作用:
如果队首元素不是 inprogress
,而是 doAnimation
方法,则先将 doAnimation
出队,再让 inprogress
入队首,再运行 doAnimation
方法;
如果队首元素是 inprogress
的话,则移除锁
如果队列为空的话,则清空 queue
,节省内存
源码:
//源码4624行 //目标元素,'type' dequeue: function( elem, type ) { //'type' type = type || "fx"; //get,获取目标元素的队列 var queue = jQuery.queue( elem, type ), //长度 startLength = queue.length, //去除对首元素,并返回该元素 fn = queue.shift(), //确保该队列有一个hooks hooks = jQuery._queueHooks( elem, type ), //next相当于dequeue的触发器 next = function() { jQuery.dequeue( elem, type ); }; // If the fx queue is dequeued, always remove the progress sentinel //如果fn='inprogress',说明是fx动画队列正在出队,就移除inprogress if ( fn === "inprogress" ) { fn = queue.shift(); startLength--; } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued //如果是fx动画队列的话,就添加inprogress标志,来防止自动出队执行 //意思应该是等上一个动画执行完毕后,再执行下一个动画 if ( type === "fx" ) { queue.unshift( "inprogress" ); } // Clear up the last queue stop function //删除hooks的stop属性方法 delete hooks.stop; //递归dequeue方法 fn.call( elem, next, hooks ); } console.log(startLength,'startLength4669') //如果队列是一个空数组,并且hooks存在的话,清除该队列 if ( !startLength && hooks ) { //进行队列清理 hooks.empty.fire(); console.log(hooks.empty.fire(),'bbbb4671') } },
解析:
循环同步运行多个 doAnimation()
方法,直到队列为空
综上,除 doAnimation
内的逻辑外, 整个 $().animate()
的流程图 为:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- ReactNative源码解析-初识源码
- Spring源码系列:BeanDefinition源码解析
- Spring源码分析:AOP源码解析(下篇)
- Spring源码分析:AOP源码解析(上篇)
- 注册中心 Eureka 源码解析 —— EndPoint 与 解析器
- 新一代Json解析库Moshi源码解析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Effective Python
布雷特·斯拉特金(Brett Slatkin) / 爱飞翔 / 机械工业出版社 / 2016-1 / 59
用Python编写程序,是相当容易的,所以这门语言非常流行。但若想掌握Python所特有的优势、魅力和表达能力,则相当困难,而且语言中还有很多隐藏的陷阱,容易令开发者犯错。 本书可以帮你掌握真正的Pythonic编程方式,令你能够完全发挥出Python语言的强大功能,并写出健壮而高效的代码。Scott Meyers在畅销书《Effective C++》中开创了一种以使用场景为主导的精练教学方......一起来看看 《Effective Python》 这本书的介绍吧!