toggleClass: function( value, stateVal ) {
var type = typeof value;//值类型 if ( typeof stateVal === "boolean" && type === "string" ) {//如果第二个参数为bool值
return stateVal ? this.addClass( value ) : this.removeClass( value );//如果第二个参为true,添加class,否则移除class
} if ( jQuery.isFunction( value ) ) {//如果第一个参数是函数
return this.each(function( i ) {
jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
});
} return this.each(function() {
if ( type === "string" ) {
// toggle individual class names
var className,
i = 0,
self = jQuery( this ),
classNames = value.match( rnotwhite ) || [];//将按空格分隔的className分割成数组 while ( (className = classNames[ i++ ]) ) {//遍历数组
// check each className given, space separated list
if ( self.hasClass( className ) ) {
self.removeClass( className );
} else {
self.addClass( className );
}
} // Toggle whole class name 如果没有传入第一个参数或者第一个参数是undefined或者第一个参数是bool值
} else if ( type === strundefined || type === "boolean" ) {
if ( this.className ) {
// store className if set
data_priv.set( this, "__className__", this.className );
} // If the element has a class name or if we're passed "false",
// then remove the whole classname (if there was one, the above saved it).
// Otherwise bring back whatever was previously saved (if anything),
// falling back to the empty string if nothing was stored.
this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
}
});
}

前面几种情况都很好理解,最后一种$("#xxx").toggleClass()则用到了data_priv对象,因为它需要将移除的className缓存起来。

data_priv是jQuery内部的缓存对象,在初始化时,它会生成一个空的cache对象用于缓存数据,还有根据jQuery.expando生成它自身的expando,此外,它还有一些方法

在调用data_priv.set()时,会首先调用data_priv.key(),因为它会在elem上通过defineProperties()为elem添加一个expano的值

比如:

之后data_priv.set中就可以在data_priv.cache中存储值:

在调用data_priv.get()时,首先也是调用data_priv.key()方法,用它来返回elem中expando的值,也就是cache中对应的键,然后就能找到存储的值了。

data_priv的源码如下:

function Data() {
// Support: Android<4,
// Old WebKit does not have Object.preventExtensions/freeze method,
// return new empty object instead with no [[set]] accessor
Object.defineProperty( this.cache = {}, 0, {//初始化定义this.cache为{}
get: function() {
return {};
}
});
this.expando = jQuery.expando + Data.uid++;//jQuery21301509336824528871
} Data.uid = 1;
Data.accepts = jQuery.acceptData; Data.prototype = {
key: function( owner ) {
// We can accept data for non-element nodes in modern browsers,
// but we should not, see #8335.
// Always return the key for a frozen object.
if ( !Data.accepts( owner ) ) {
return 0;
} var descriptor = {},
// Check if the owner object already has a cache key unlock = owner[ this.expando ];
// If not, create one
if ( !unlock ) {
unlock = Data.uid++;//3 // Secure it in a non-enumerable, non-writable property
try {
descriptor[ this.expando ] = { value: unlock };
Object.defineProperties( owner, descriptor );
//console.log(owner[this.expando]);//3 // Support: Android<4
// Fallback to a less secure definition
} catch ( e ) {
descriptor[ this.expando ] = unlock;
jQuery.extend( owner, descriptor );
}
} // Ensure the cache object if ( !this.cache[ unlock ] ) {//undefined
this.cache[ unlock ] = {};
}
return unlock;//
},
set: function( owner, data, value ) {
var prop,
// There may be an unlock assigned to this node,
// if there is no entry for this "owner", create one inline
// and set the unlock as though an owner entry had always existed
unlock = this.key( owner ),//3
cache = this.cache[ unlock ];//{} // Handle: [ owner, key, value ] args
if ( typeof data === "string" ) {
cache[ data ] = value; // Handle: [ owner, { properties } ] args
} else {
// Fresh assignments by object are shallow copied
if ( jQuery.isEmptyObject( cache ) ) {
jQuery.extend( this.cache[ unlock ], data );
// Otherwise, copy the properties one-by-one to the cache object
} else {
for ( prop in data ) {
cache[ prop ] = data[ prop ];
}
}
}
return cache;
},
get: function( owner, key ) {
// Either a valid cache is found, or will be created.
// New caches will be created and the unlock returned,
// allowing direct access to the newly created
// empty data object. A valid owner object must be provided.
var cache = this.cache[ this.key( owner ) ]; return key === undefined ?
cache : cache[ key ];
},
access: function( owner, key, value ) {
var stored;
// In cases where either:
//
// 1. No key was specified
// 2. A string key was specified, but no value provided
//
// Take the "read" path and allow the get method to determine
// which value to return, respectively either:
//
// 1. The entire cache object
// 2. The data stored at the key
//
if ( key === undefined ||
((key && typeof key === "string") && value === undefined) ) { stored = this.get( owner, key ); return stored !== undefined ?
stored : this.get( owner, jQuery.camelCase(key) );
} // [*]When the key is not a string, or both a key and value
// are specified, set or extend (existing objects) with either:
//
// 1. An object of properties
// 2. A key and value
//
this.set( owner, key, value ); // Since the "set" path can have two possible entry points
// return the expected data based on which path was taken[*]
return value !== undefined ? value : key;
},
remove: function( owner, key ) {
var i, name, camel,
unlock = this.key( owner ),
cache = this.cache[ unlock ]; if ( key === undefined ) {
this.cache[ unlock ] = {}; } else {
// Support array or space separated string of keys
if ( jQuery.isArray( key ) ) {
// If "name" is an array of keys...
// When data is initially created, via ("key", "val") signature,
// keys will be converted to camelCase.
// Since there is no way to tell _how_ a key was added, remove
// both plain key and camelCase key. #12786
// This will only penalize the array argument path.
name = key.concat( key.map( jQuery.camelCase ) );
} else {
camel = jQuery.camelCase( key );
// Try the string as a key before any manipulation
if ( key in cache ) {
name = [ key, camel ];
} else {
// If a key with the spaces exists, use it.
// Otherwise, create an array by matching non-whitespace
name = camel;
name = name in cache ?
[ name ] : ( name.match( rnotwhite ) || [] );
}
} i = name.length;
while ( i-- ) {
delete cache[ name[ i ] ];
}
}
},
hasData: function( owner ) {
return !jQuery.isEmptyObject(
this.cache[ owner[ this.expando ] ] || {}
);
},
discard: function( owner ) {
if ( owner[ this.expando ] ) {
delete this.cache[ owner[ this.expando ] ];
}
}
};
var data_priv = new Data();
var data_user = new Data();

jQuery toggleClass 源码解读的更多相关文章

  1. jQuery.Callbacks 源码解读二

    一.参数标记 /* * once: 确保回调列表仅只fire一次 * unique: 在执行add操作中,确保回调列表中不存在重复的回调 * stopOnFalse: 当执行回调返回值为false,则 ...

  2. jQuery attr() 源码解读

    我们知道,$().attr()实质上是内部调用了jQuery.access方法,在调用时jQuery.attr作为回调传入.在通过种种判断(参看jQuery.access()方法)之后,取值和赋值最后 ...

  3. jquery.fileupload源码解读笔记

    基础编程风格 新建 test.html  和 test.js和 main.js和 无论哪种顺序 <body> <script src="/Sandeep/js/jquery ...

  4. jQuery.extend()源码解读

    // extend方法为jQuery对象和init对象的prototype扩展方法// 同时具有独立的扩展普通对象的功能jQuery.extend = jQuery.fn.extend = funct ...

  5. jQuery框架源码解读

    1.jQuery 1.9.1 parseJSON: function( data ) { // Attempt to parse using the native JSON parser first ...

  6. jQuery position() 源码解读

    position的代码比较简单... position: function() { if ( !this[ 0 ] ) { return; } var offsetParent, offset, el ...

  7. jquery offsetParent()源码解读

    offsetParent: function() { return this.map(function() { var offsetParent = this.offsetParent || docE ...

  8. jQuery addClass() 源码解读

    addClass: function( value ) { var classes, elem, cur, clazz, j, i = 0, len = this.length, proceed = ...

  9. jQuery removeAttr() 源码解读

    removeAttr比attr的代码要简单很多~~~ removeAttr: function( name ) { return this.each(function() { jQuery.remov ...

随机推荐

  1. socket技术与负载均衡

    网络编程 Nginx1.9之前使用 Lvs  Haproxy 实现四层反向和负载均衡 Lvs可以i应用到所有负载均衡的功能 数据库 web服务等 四层负载均衡,根据连接进行保存. 断开,连接.进行轮训 ...

  2. 【应用】SVG饼状图

    <!DOCTYPE html> <html> <head> <title></title> </head> <body o ...

  3. distutils 打包setup.py

    from distutils.core import setup setup(name='hello', version='1.0', description='test example', auth ...

  4. LeetCode 889. Construct Binary Tree from Preorder and Postorder Traversal

    原题链接在这里:https://leetcode.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal/ 题 ...

  5. android手机各大分区详解

    1. bootloader  当我们拿到一款手机,第一件事应该就是按下电源键开机,那么从开机到进入到桌面程序这中间发生了些什么呢,我们从下面这张简化了的手机结构图开始: 注意:该结构图并不反映手机的实 ...

  6. disablescroll

    页面的设置 disablescroll:true(需要配合设置 enablePullDownRefresh:false ) 可以实现页面上下不能滑动 另一种实现方法: 设置页面的根元素 绝对定位, p ...

  7. zabbix snmp、jmx配置使用

    SNMP: snmp是很古老的监控,我萌几乎可以在所有设备上看到它的身影 [root@linux-node1 ~]# yum install net-snmp net-snmp-libs net-sn ...

  8. Lecture 0 --基本说明

    Abstract:本章所记录的知识是后面章节需要的前导知识,请务必仔细读本章,理解涉及的知识点,方便后面章节的学习.本次数据结构笔记主要参考殷人昆的<数据结构(C语言描述)>这本书,需要的 ...

  9. Android开发--Activity

    一:Activity生命周期 (1)Activity生命周期中的几种方法: protected void onCreate(Bundle savedInstanceState): protected  ...

  10. ASP.NET Core编程实现基本身份认证

    概览 在HTTP中,基本认证(Basic access authentication,简称BA认证)是一种用来允许网页浏览器或其他客户端程序在请求资源时提供用户名和口令形式的身份凭证的一种登录验证方式 ...