学习jQuery源码-样式操作之addClass
字数:6643
作者:Jerry
本系列文章是学习jQuery源码的笔记,基于网络的各种教程与自己的理解而写(不会覆盖到每个点,可能存在错误),一来是记录学习成果;),以后要用到时能方便找到;二来也帮助一下需要的人。
样式操作的API
jQuery提供了一些API来操作css样式,API如下:
- .addClass():对元素的样式操作,底层的实现就是修改元素的className值。
- .hasClass() 为匹配的元素集合中的每个元素中移除一个属性(attribute)。
- .removeClass()为集合中匹配的元素删除一个属性(property)。
- .toggleClass()获取匹配的元素集合。
现在开始分析每个API:
.addClass( className )
函数介绍
描述:为每个匹配的元素添加指定的样式类名。
功能:
- 增加一个样式名: .addClass('class1')
- 增加多个样式名: .addClass('class1 class2')
传入函数,为每个匹配元素分别设置样式名:
$("ul li:last").addClass(function(index) { return "item-" + index; });// 给定一个有2个<li>元素的无序列表,则将在最后一个<li>元素上加上"item-1"样式。
源码分析
// 为匹配的每个元素增加指定的class(es)
addClass: function( value ) {
var classes, elem, cur, clazz, j,
i = 0,
len = this.length,
// value是字符串,则proceed赋值value,
// 否则proceed=false
proceed = typeof value === "string" && value;
// 如果传递的是回调函数,递归调用
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
// 回调函数获得的参数是 元素index, 元素已有className
jQuery( this ).addClass( value.call( this, j, this.className ) );
});
}
if ( proceed ) {
// The disjunction here is for better compressibility (see removeClass)
// 通过正则/\S+/g 分组,按空格切分样式名
classes = ( value || "" ).match( core_rnotwhite ) || [];
for ( ; i < len; i++ ) {
elem = this[ i ];
//如果元素本身存在class样式,先取出来
cur = elem.nodeType === 1 && ( elem.className ?
( " " + elem.className + " " ).replace( rclass, " " ) :
" "
);
//""等于false;但" "却等于true
if ( cur ) {
j = 0;
while ( (clazz = classes[j++]) ) {//遍历取出所有样式名
if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
cur += clazz + " ";//不存在该样式,则加入
}
}
elem.className = jQuery.trim( cur );//设置新样式
}
}
}
return this;
},
代码可简要分为5步:
- 参数value是函数,递归调用;
- 用空格切分样式为数组;
- 获取当前样式并取出来;
- 组合样式数组成新样式名;
- 通过className 设置新的样式。
代码清晰简单,现在重点讲一下传入回调函数怎么处理的?
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
jQuery( this ).addClass( value.call( this, j, this.className ) );
});
}
this.each遍历当前元素集,给回调函数传入参数 当前元素index, 当前元素的className,获取回调函数返回值作为新的value,然后递归调用addClass。
.removeClass( [className] )
描述: 移除集合中每个匹配元素上一个,多个或全部样式。
removeClass: function( value ) {
var classes, elem, cur, clazz, j,
i = 0,
len = this.length,
proceed = arguments.length === 0 || typeof value === "string" && value;
if ( jQuery.isFunction( value ) ) {
return this.each(function( j ) {
jQuery( this ).removeClass( value.call( this, j, this.className ) );
});
}
if ( proceed ) {
classes = ( value || "" ).match( core_rnotwhite ) || [];
for ( ; i < len; i++ ) {
elem = this[ i ];
// This expression is here for better compressibility (see addClass)
cur = elem.nodeType === 1 && ( elem.className ?
( " " + elem.className + " " ).replace( rclass, " " ) :
""
);
if ( cur ) {
j = 0;
while ( (clazz = classes[j++]) ) {
// Remove *all* instances
while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
cur = cur.replace( " " + clazz + " ", " " );
}
}
elem.className = value ? jQuery.trim( cur ) : "";
}
}
}
return this;
},
代码与addClass很相似,不再累述。但要注意一点,elem.className = value ? jQuery.trim( cur ) : "";
设置新样式很巧妙,先判断了value,value不存在,则删除全部样式名。
.hasClass( className )
描述: 确定任何一个匹配元素是否有被分配给定的(样式)类。
hasClass: function( selector ) {
var className = " " + selector + " ",
i = 0,
l = this.length;
for ( ; i < l; i++ ) {
// 必须是Element,技巧同样是前后加空格,同样是indexOf
if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
return true;
}
}
return false;
},
代码简单,就2个点说一下:
- 当前元素集中有一个元素有该class就返回true;
rclass = /[\t\r\n\f]/g
,该正则就是把 制表符、换行符等换成空格" "。
.toggleClass( className )
描述: 在匹配的元素集合中的每个元素上添加或删除一个或多个样式类,取决于这个样式类是否存在或值切换属性。即:如果存在(不存在)就删除(添加)一个类。
toggleClass()接受一个或多个class;自从jQuery1.4以后,如果没有为.toggleClass()指定参数,元素上的所有class名称将被切换。
toggleClass: function( value, stateVal ) {
var type = typeof value;
// 是否有开关,有的话直接按开关添加/删除样式
if ( typeof stateVal === "boolean" && type === "string" ) {
return stateVal ? this.addClass( value ) : this.removeClass( value );
}
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( core_rnotwhite ) || [];
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
// toggle所有样式
} else if ( type === core_strundefined || type === "boolean" ) {
if ( this.className ) {
// store className if set
// 存储当前的样式
data_priv.set( this, "__className__", this.className );
}
// 元素有样式名或者传参false,删除所有样式
// 否则从前面存储的恢复,若没有存储,则置为""
this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
}
});
},
toggleClass就是addClass、removeClass、hasClass的综合运用。
结束
本篇是jQuery的css操作的样式名操作,也就是addClass、removeClass、hasClass及toggleClass四个函数。下一篇继续分析jQuery的css操作。