1、$()
.addClass()
做用:
向目標元素添加一個或多個類名javascript
源碼:html
//向目標元素添加一個或多個類名
//源碼8401行
addClass: function( value ) {
var classes, elem, cur, curValue, clazz, j, finalValue,
i = 0;
//若是addClass(value)的value是一個function
//那麼就經過call讓目標元素this調用該function
if ( isFunction( value ) ) {
return this.each( function( j ) {
// function(index,currentclass)
// index 對應 j,做用是獲取多個目標元素的下標;
// currentClass 對應 getClass(this),做用是獲取當前元素的類名,方便加空格
jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
} );
}
//將(多個)類名轉爲數組形式
classes = classesToArray( value );
if ( classes.length ) {
//多個目標元素
while ( ( elem = this[ i++ ] ) ) {
//獲取當前值
curValue = getClass( elem );
//若是目標元素是元素節點而且用空格左右包起來 " "+value+" "
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
if ( cur ) {
j = 0;
//一個個類名
while ( ( clazz = classes[ j++ ] ) ) {
//當前元素沒有和要添加的類名重複的話就添加
if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
cur += clazz + " ";
}
}
//最後,確認通過處理後的類名集合是否和處理前的類名集合相同
//若是相同,就setAttribute,從新渲染,不然不從新渲染(性能優化)
// Only assign if different to avoid unneeded rendering.
finalValue = stripAndCollapse( cur );
if ( curValue !== finalValue ) {
//最後經過setAttribute,添加類名
elem.setAttribute( "class", finalValue );
}
}
}
}
return this;
},
複製代碼
解析:
(1)getClass()
做用:
獲取目標元素的類名java
源碼:node
//源碼8377行
function getClass( elem ) {
return elem.getAttribute && elem.getAttribute( "class" ) || "";
}
複製代碼
(2)classesToArray
做用:
將(多個)類名轉爲數組形式express
源碼:數組
//源碼8382行
function classesToArray( value ) {
//元素的className若是有多個類名的話,是以數組形式保存的,那就直接返回
if ( Array.isArray( value ) ) {
return value;
}
//若是元素類名是string類型的話
if ( typeof value === "string" ) {
return value.match( rnothtmlwhite ) || [];
}
return [];
}
複製代碼
(3)stripAndCollapse
做用:
將vaues以空格分開,再以空格拼接性能優化
源碼:app
// 源碼8370行
// Strip and collapse whitespace according to HTML spec
// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
function stripAndCollapse( value ) {
var tokens = value.match( rnothtmlwhite ) || [];
return tokens.join( " " );
}
複製代碼
綜上:
能夠看到 addClass() 的思路是:
① 獲取元素當前類名集合 a
② 若是要添加的類名 b 不重複,則將 b 添加進 a 裏
③ 最後使用elem.setAttribute("class",a)
完成性能
2、$()
.removeClass
做用:
移除類,若是沒有參數,則移除目標元素全部類名優化
源碼:
//源碼8449行
removeClass: function( value ) {
var classes, elem, cur, curValue, clazz, j, finalValue,
i = 0;
//做用同上
if ( isFunction( value ) ) {
return this.each( function( j ) {
jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
} );
}
//若是沒有規定參數,則刪除全部類
if ( !arguments.length ) {
return this.attr( "class", "" );
}
//將(多個)類名轉爲數組形式
classes = classesToArray( value );
if ( classes.length ) {
while ( ( elem = this[ i++ ] ) ) {
curValue = getClass( elem );
// This expression is here for better compressibility (see addClass)
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
if ( cur ) {
j = 0;
while ( ( clazz = classes[ j++ ] ) ) {
// 若是當前元素的類名裏有要移除的類,
// 就將該類替換成" "
// Remove *all* instances
while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
cur = cur.replace( " " + clazz + " ", " " );
}
}
//同上
// Only assign if different to avoid unneeded rendering.
finalValue = stripAndCollapse( cur );
if ( curValue !== finalValue ) {
elem.setAttribute( "class", finalValue );
}
}
}
}
return this;
},
複製代碼
能夠看到 addClass() 的思路是:
① 獲取元素當前類名集合 a
② 若是要移除的類名 b 不重複,則將 a 裏面的 b 替換成空格 " "
③ 最後使用elem.setAttribute("class",a)
完成移除類名
3、$()
.toggleClass
做用:
切換類
源碼:
//stateVal爲true,則添加類,false則移除類
//源碼8497行
toggleClass: function( value, stateVal ) {
var type = typeof value,
//若是value是string類型或者是數組類型的話,爲true,反之爲false
isValidValue = type === "string" || Array.isArray( value );
//true添加類,false移除類
if ( typeof stateVal === "boolean" && isValidValue ) {
return stateVal ? this.addClass( value ) : this.removeClass( value );
}
//同上
if ( isFunction( value ) ) {
return this.each( function( i ) {
jQuery( this ).toggleClass(
value.call( this, i, getClass( this ), stateVal ),
stateVal
);
} );
}
return this.each( function() {
var className, i, self, classNames;
if ( isValidValue ) {
// Toggle individual class names
i = 0;
self = jQuery( this );
classNames = classesToArray( value );
while ( ( className = classNames[ i++ ] ) ) {
//若是目標元素已經有要toggle的className,那麼就移除它
// Check each className given, space separated list
if ( self.hasClass( className ) ) {
self.removeClass( className );
} else {
//不然就添加類
self.addClass( className );
}
}
// Toggle whole class name
}
//若是$.toggleClass()沒有值或者該值爲布爾值
else if ( value === undefined || type === "boolean" ) {
className = getClass( this );
//若是目標元素有類的話,就先用__className__屬性保存類名
if ( className ) {
// Store className if set
dataPriv.set( this, "__className__", 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.
//若是目標元素存在setAttribute的方法話
if ( this.setAttribute ) {
//若是已有類名/value=false,則移除全部類名
//若是沒有類名而且value=true,
//則從dataPriv中從新獲取以前保存過的__className__當作目標元素的類名
this.setAttribute( "class",
className || value === false ?
"" :
dataPriv.get( this, "__className__" ) || ""
);
}
}
} );
},
複製代碼
解析:
主要是兩個 if
(1) if ( typeof stateVal === "boolean" && isValidValue )
這個就是$()
.toggleClass(value,truefalse) 的第二個參數的做用了,
true 即 addClass(),false 即 removeClass()
(2)if(isValidValue )
這個是隻有一個參數的狀況
利用 hasClass 判斷是否 add/removeClass
(3)若是$.toggleClass()沒有值或者第一個值爲 true 的話
若是目標元素有類名的話,就使用dataPriv
來保存類名,
若是目標元素有setAttribute
的話,則將 className 設置爲dataPriv
裏保存的值。
4、$()
.hasClass
做用:
檢查目標元素是否包含指定的類
源碼:
//源碼8568行
hasClass: function( selector ) {
var className, elem,
i = 0;
className = " " + selector + " ";
while ( ( elem = this[ i++ ] ) ) {
if ( elem.nodeType === 1 &&
//關鍵代碼
( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
return true;
}
}
return false;
}
複製代碼
這個代碼還挺簡單的,就不解析了。
(完)