内容简介:前言:需要先看
前言:
需要先看 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源码解析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
腾讯网UED体验设计之旅
任婕 等 / 电子工业出版社 / 2015-4 / 99.00元
《腾讯网UED体验设计之旅》是腾讯网UED的十年精华输出,涵盖了丰富的案例、极富冲击力的图片,以及来自腾讯网的一手经验,通过还原一系列真实案例的幕后设计故事,从用户研究、创意剖析、绘制方法、项目管理等实体案例出发,带领读者经历一场体验设计之旅。、 全书核心内容涉及网媒用户分析与研究方法、门户网站未来体验设计、H5技术在移动端打开的触控世界、手绘原创设计、改版迭代方法、文字及信息图形化设计、媒......一起来看看 《腾讯网UED体验设计之旅》 这本书的介绍吧!