jQuery源码分析系列:CSS-class样式
jQuery提供了4个操作class的方法:
jQuery.fn.extend({ // ... // 为匹配的每个元素增加指定的class(es) addClass: function( value ) {}, // 从匹配的每个元素上,移除 一个 或 多个 或 全部class removeClass: function( value ) {}, // 对匹配元素集中的每个元素增加或删除一个或多个class toggleClass: function( value, stateVal ) {}, // 检测匹配的元素是否指定了传入的class,只要有一个匹配就返回true hasClass: function( selector ) {}, // ... });
.addClass():
为匹配的每个元素增加指定的class(es)
.addClass(className):className添加到每一个匹配元素的class属性上的一个或多个class
.addClass(function(index,currentClass)):function(index,currentClass)返回一个或多个class名称,多个class用空格分开这些class被添加到现有的class属性中
index 单签元素在集合中的位置 currentClass 当前的class名 this 指向集合中的当前元素
addClass:function(value){ var classNames,i,l,elem,setClass,c,cl; //value为函数 if(jQuery.isFunction(value)){ return this.each(function(j){ //this.className 获取当前的class的值 jQuery(this).addClass(value.call(this,j,this.className)); }); } //vlaue为数组 if(value && typeof vlaue === "string"){ classNames = value.split(rspace);//用空白符风格classNames 转换为数组 for(i=0,l=this.length;i<l;i++){//遍历所有匹配的元素 缓存长度 elem = this[i];//缓存下来 避免再次查找 if(elem.nodeType === 1){ //如果没有class属性 或class属性为空字符串 classNames.length ===1 ,多于一个去重 if(!elem.className && classNames.length === 1){ elem.className = value; }else{//已有className 或 classNames长度大于1 setClass = " " + elem.className + " "; for(c = 0;cl = classNames.length;c<cl:c++){ //不理解 if(!~setClass.indexOf(" " + classNames[c] + " ")){ setClass += classnames[c] + " ";//追加,最后加一个空格 } } //去除首尾空白符 elem.className = jQuery.trim(setClass); } } } } },
.removeClass():
从匹配的每个元素上,移除 一个 或 多个 或 全部class
如果是函数,执行函数,将返回结果再次调用jQuery.fn.removeClass
如果是字符串,在elem.className和classNames[c]前后加空格,判断replace删除
如果是undefined,置为空字符串elem.className = ""
className 一个或多个以空格分隔的class,这些class将被从匹配元素的class属性中移除
.removeClass( function(index, class) )
function(index, class) 函数返回一个或多个以空格分隔的class,用于移除。
removeClass:function(value){ var classNames,i,l,elem,className,c,cl; //如果传入函数则执行函数 取返回值作为要移除的classNames if(jQuery.isFunction(value)){ return this.each(function(j){ //this.calssName 获取当前的class值 jQuery(this).removeClass(value.call(this,j,this.className)); }); } if((value && typeof value === "string") || value === undefined){ // value || "" 避免空引用错误的常用技巧 classNames = (value || "").split(rspace);//分割数组 for(i=0,l=this.length;i<l;i++){//遍历所有匹配的元素 缓存长度 elem = this[i];//缓存下来 避免再次查找 if(elem.nodeType === 1 && elem.className){ //如果有value,则从当前className属性中删除 if(value){ className = (" " + elem.className + " ").replace(rclass," ");//前后加空格 将\n \t \r替换为空格 for(c = 0;cl = classNames.length;c<cl:c++){ className = className.replace(" " + classNames[c] + " "," ");//将要删除的className替换为空格 } // 删除前后的空白符,然后赋值给elem.className elem.classname = jQuery.trim(className); }else{ elem.className = ""; } } } return this; },
.toggleClass():
对匹配元素集中的每个元素增加或删除一个或多个class
增加或删除的行为依赖当前元素是否含有指定的class,或switch参数的值
.toggleClass( className ) 1.0
className 一个或多个class(用空格隔开),在匹配元素集的每个元素上切换class
如果集合中的某个元素含有指定的className,className会被删除;如果没有会添加。
.toggleClass( className, switch ) 1.3
switch 一个布尔值,依据这个布尔值来决定是添加(true)还是删除(false)
.toggleClass( [switch] ) 1.4
switch 一个布尔值,依据这个布尔值来决定是添加还是删除
.toggleClass( function(index, class, switch) [, switch] ) 1.4
function(index, class, switch) 函数返回用于切换的calss名称
index是当前元素是集合中的下标位置, class是当前元素的就class值
核心技巧:调用addClass 或 removeClass 或 直接赋值elem.className
toggleClass: function( value, stateVal ) { var type = typeof value, // value的类型,可以是字符串(一个或多个class),也可以是function,(undefined和boolean是另说) isBool = typeof stateVal === "boolean"; // 如果是函数,则执行函数,用函数的返回值作为切换的className,迭代调用jQuery.fn.toggleClass if ( jQuery.isFunction( value ) ) { return this.each(function( i ) { // 迭代调用 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); }); } // 遍历当前jQuery对象 return this.each(function() { // value是字符串,挨个遍历value中的类样式,switch的优先级高于hasClass,hasClass返回false则addClass返回true则removeClass if ( type === "string" ) { // toggle individual class names // 切换单个class var className, i = 0, self = jQuery( this ), state = stateVal, classNames = value.split( rspace ); // 可能有多个class,用空白符分割 // 因为不需要在className前后加空格,所以这里可以将取值、自增、判断合并为while循环。很好的技巧。 while ( (className = classNames[ i++ ]) ) { // check each className given, space seperated list /* * 如果state是布尔值,则以state为准,否则检查是否含有className * 含有 state为false,表示需要addClass;反之需要removeClass * 这个三元表达式合并了state与self.hasClass的判断,小技巧 */ state = isBool ? state : !self.hasClass( className ); //删除还是添加 self[ state ? "addClass" : "removeClass" ]( className ); } /* * type === "undefined" 未指定参数,即.toggleClass() * type === "boolean" 省略className,只有switch,即.toggleClass( switch ) */ // 未指定参数 或 只有switch,则切换整个className } else if ( type === "undefined" || type === "boolean" ) { // 如果有className,则缓存下来,以便再次调用时恢复 if ( this.className ) { // 以内部数据的方式缓存 jQuery._data( this, "__className__", this.className ); } /* * 切换整个className * 又是一个合并了几个判断条件的三元,分解为四个逻辑: * this.className && value 是 true/undefined "" * this.className && value 是 false "" * !this.className && value 是 true/undefined jQuery._data( this, "__className__" ) || "" * !this.className && value 是 false "" * * 分析一下上边的四个逻辑,可以总结如下:(value用switch代替) * 1. 如果this.className存在,无论switch什么状态(true/false/undefined),都置为空"" * 2. 如果this.className不存在,如果switch为true/undefined,才会恢复className * 3. 如果this.className不存在,如果switch为false,置空(保持不变) * * .toggleClass( switch )的用法可以总结如下: * 1. switch为true,进行正常的切换,等价于.toggleClass() * 2. switch为false,总是置空 */ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; } }); },
.hasClass():
检测匹配的元素是否指定了传入的class,只要有一个匹配就返回true
.hasClass() 检测匹配的元素是否指定了传入的class,只要有一个匹配就返回true;元素可能有多个class,在HTML中多个class用空格隔开;
如果遇到某个元素含有指定的className,.hasClass()将会返回true,即便还指定了其他的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 + " ").replcae(rclass," ").indexOf(className) > -1){ return true; } } return false; }
posted on 2013-04-11 17:21 color_story 阅读(177) 评论(0) 编辑 收藏 举报