jQuery从入门到精通源码分析系列(三十九) 动画队列
沉沙 2018-07-24 来源 : 阅读 1236 评论 0

摘要:本篇jQuery教程探讨了动画队列的相关内容,希望阅读本篇文章以后大家有所收获,帮助大家对jQuery的理解更加深入。

data函数在jQuery中只有短短的300行代码,非常不起点 ,剖析源码的时候你会发现jQuery只要在有需要保存数据的地方无时无刻不依赖这个基础设施

动画会调用队列,队列会调用data数据接口还保存队列里面的的动画数据

所以我们在自习回顾下关于数据缓存

//These may be used throughout the jQuery core codebase

//存数据的

//用户使用

data_user = new Data();//存储对象

//jQuery内部私有

//用来存事件的, 如click事件那种

data_priv = new Data();

data在jQuery中有两种

一个是用来存数据的, 对应的对象分别是

存储对象: data_user

获取与设置方法: $.data(el, key, value)

另一个是用来存事件的,动画数据的

存储对象: data_priv

获取与设置方法: $._data(el, key, value)

data_user和data_priv, 就如其名, 一个是用户用的, 一个是jQuery私有的, 他们都是一个叫Data的实例对象

为什么要设置这2个数据接口类?

jQuery的设置都是维护一个jQuery的数据对象,所以

只是实现data的接口,比如:

$('#aaron').data('key', 'value')

实现链式的.data接口,这种很简单,我们可以把简单的数据缓存到jquery内部的这个对象上

方法可以这样实现

直接在实例上fn的接口上扩充

$.fn.data = function(k, v) {

    return this.each(function() {

        this[key] = v //把接口data的value保存在dom对象上    })

    return this

}

这个很简单把数据直接保存在dom对象上

当然针对基本类型这样处理当然也是可以的,如果是引用类型,函数对象呢?这样处理可以吗?

$('#aaron').data('nodeValue', '11111')

$('#aaron').data('key', function(){

    //操作

})

问题来了:

1:这样会更改DOM本身的属性值,当然能不能生效还不说

2:传递可是引用类型哦,不靠谱的内存回收,说不定就溢出了

3:数据暴露,容易被直接改写

如何解决这些问题? jQuery就引入了数据对象这个概念

先不管内部怎么实现,先看节点的属性

多了一个灰色的自定义的key与value

灰色意味着不能通过for枚举出来,这种设置在ES5中,是有API直接支持了

// If not, create oneif (!unlock) {

    unlock = Data.uid++;

    // Secure it in a non-enumerable, non-writable property

    try {

        descriptor[this.expando] = {

            value: unlock

        };

        Object.defineProperties(owner, descriptor);

        // Support: Android < 4

        // Fallback to a less secure definition

    } catch (e) {

        descriptor[this.expando] = unlock;

        jQuery.extend(owner, descriptor);

    }

}

看注释就清晰了,这个属性是受保护的,不能被改写

OK了。通过这样一个唯一的桥接标志,我们可以做一个ORM的映射了,让dom与一个数据缓存接口产生一一对应的关系

动画队列用到的数据缓存

jQuery为了实现动画队列的链式调用,所以必须先在实例就是原型上先扩展一个方法啊,然后在内部才能调用底层的方法

当然jQuery基本所有的层次都是这样的结构,除了链式之外,还可以把具体的实例方法与原型方法通用

//静态jQuery.extend//实例

.extend

动画的实例方法

this.queue(optall.queue, doAnimation);

调用实例方法中基于动画的扩展接口

jQuery.fn.extend({

    queue

    dequeue

    delay

    clearQueue

    promise

queue: function(type, data) {

    var setter = 2;

    //修正type, 默认为表示jquery动画的fx, 如果不为"fx",

    //即为自己的自定义动画, 一般我们用"fx"就足够了.  

    if (typeof type !== "string") {

        data = type;

        type = "fx";

        setter--;

    }

    //只有动画的回调

    // div.slideToggle(1000);

    // div.slideToggle("fast");

    // div.animate({left:'-=200'},1500);

    // div.queue('fx')

    if (arguments.length < setter) {

        return jQuery.queue(this[0], type);

    }

    return data === undefined ?

        this :

        this.each(function() {

            //调用基础队列

            //设置动画队列缓存

            //并返回队列总数

            var queue = jQuery.queue(this, type, data);

            // ensure a hooks for this queue

            jQuery._queueHooks(this, type);

            //直接执行动画队列

            //防止在执行函数的时候, 这里又进行dequeue操作, 这样会同时执行2个函数, 队列就不受控制了.  

            if (type === "fx" && queue[0] !== "inprogress") {

                //如果队列没有被锁住, 即此时没有在执行dequeue. 移出队列里第一个函数并执行它.  

                jQuery.dequeue(this, type);

            }

        });

},

实例的queue接口只是做了2个情况的判断,一种是传递fx,一种是设置队列,底层还是通过jQuery.queue静态方法处理的

分析一组动画:

div.show(1000);

div.hide(2000)

div.show(3000)

1 有时间参数的接口,是肯定需要执行动画的,同一个接口上有多个动画接口,那么就会意味着需要队列来管理执行顺序

2 管理队列引入数据缓存,缓存需要载体node节点,所以动画的扩展的接口在最上层设计是可以直接跟DOM链式

逻辑上肯定是线性的执行,show执行完毕,然后取出hide执行,完毕后在取出show执行

那么动画的调用是如何组织的?

理论上3个动画,在cache中有3个缓存的data我们查看下

为了便于查看,我把代码改了下 增加了一个标示 Aaron 对应的是时间

在执行div.show(3000)的时候,我们查看下缓存

发现0位置的div.show(1000);被inprogress给替代了

可以猜测下第一个动画已经在开始执行了,那么它在队列中会用一个占位符用来通知后面,我这个动画还在进行,后面的动画先等等

inprogress”进程锁是这样工作的:

如果是dequeue操作, 去掉锁, 执行队列里的函数, 同时给队列加上锁. 如果是queue操作, 要看锁的状态, 如果被锁上了, 就只执行队列的添加操作. 不再调用dequeue.其实dequeue和queue都可以执行队列里的第一个函数.queue操作添加完队列之后, 会调用dequeue方法去执行函数.

用dequeue执行函数的时候, 这时候如果又用queue触发dequeue的话, 很可能同时有2个函数在执行. 队列就失去一大半意义了(还是可以保证顺序, 但是2个动画会同时执行).不过这个锁只能保证在dequeue的时候, 不被queue操作意外的破坏队列.

如果人为的同时用2个dequeue, 还是会破坏动画效果的. 所以要把fn写在回调函数里

我们在第一次做push的时候就会开始执行了动画,这样可以让速度更优

.queue(1000) , .queue(2000) , queue(3000)

if (type === "fx" && queue[0] !== "inprogress") {

    //如果队列没有被锁住, 即此时没有在执行dequeue. 移出队列里第一个函数并执行它.  

    jQuery.dequeue(this, type);

}

当第一个动画执行完毕后,那么必须有一个回调通知这个去把队列中下一个执行给取出来,然后要删掉这个占位,依次循环

opt.complete = function() {

    if (jQuery.isFunction(opt.old)) {

        opt.old.call(this);

    }

    if (opt.queue) {

        jQuery.dequeue(this, opt.queue);

    }

};


本文由职坐标整理发布,更多相关内容,请关注职坐标WEB前端jQuery频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程