jQuery 2.0.3 原始碼分析 樣式操作
根據API分類
CSS
.addClass()
對元素的樣式操作,底層的實現就是修改元素的className值
實現的功能:
增加一條樣式規則: .addClass(‘myClass’)
增加多條樣式規則: .addClass(‘myClass yourClass’)
傳遞迴調遍歷樣式規則:
$("ul li:last").addClass(function(index) { return "item-" + index; });
從介面傳參去分析這個實現手法:
原始碼:
addClass原始碼
我把程式碼簡略的分了5個步驟
- 如果傳遞的是回撥函式,遞迴呼叫
- 分解下樣式規則,通過正則/\S+/g 空白分組
- 如果元素本身存在class樣式,先取出來
- 組合成新的規則按照空格分開
- 通過className 設定新的樣式
傳遞一個引數與多個引數的處理無非就是字串的拼接,這裡就不詳講,看看程式碼就能理解
重點說一下傳遞迴調函式的設計
官方給的測試案例
HTML結構
<p class ='selected highlight'>Goodbye</p> <p class ='selected1 highlight1'>Goodbye</p> <p class ='selected2 highlight2'>Goodbye</p>
增加樣式程式碼
$(p).addClass(function(index,className){ // index className // 0 "selected highlight" // 1 "selected1 highlight1" // 2 "selected2 highlight2" });
遍歷出所有的P節點,並找其對應的class,返回給每一個回撥函式
看看原始碼的設計
//如果傳遞的是回撥函式,遞迴呼叫 ⑴ if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { //each addClass回撥 jQuery( this ).addClass( value.call( this, j, this.className ) ); }); }
不管是寫外掛還是其他的,只要是設計操作DOM的在jQuery內部就的到 this.each方法
原因很簡單,jQuery就是一個數組儲存著所有對應的節點的下標
內部在傳遞一個編寫好的回撥函式,傳遞給each方法
each方法理解就是一個迴圈方法,分解出jQuery陣列中每一個下標元,然後把每一個元素返回給外部回撥
這裡在進步替換下程式碼就很明顯了
function( i, obj[ i ] ) { //each addClass回撥 jQuery( this ).addClass( value.call( this, j, this.className ) ); }
這裡的this是指向的每一個p元素節點,因為callback.call了一下,把每一個上下文指定到當前的函數了,所以this就是對應的obj[i]
最後執行的程式碼就是
value.call( this, j, this.className )
value就是最外層使用者定義的回調了
$(p).addClass(function(index,className){ // index className // 0 "selected highlight" // 1 "selected1 highlight1" // 2 "selected2 highlight2" });
這裡意外的發現jQuery Api沒給出
還包裝了一層jQuery( this ).addClass
那麼意味著,jQuery還可以接受使用者最外層的返回引數,然後再呼叫addClass給當前節點增加新的類名
jQuery( this ).addClass( value.call( this, j, this.className ) );
p.addClass(function(index,className){ return 'aaaa' });
.removeClass( [className ] )
程式碼跟結構與addClass很相似
removeClass原始碼
.hasClass
.hasClass() 檢測匹配的元素是否指定了傳入的class,只要有一個匹配就返回true;
元素可能有多個class,在HTML中多個class用空格隔開;
如果遇到某個元素含有指定的className,.hasClass()將會返回true,即便還指定了其他的className。
/** * 檢測匹配的元素是否指定了傳入的class,只要有一個匹配就返回true * .hasClass( className ) * className 要查詢的class * 核心技巧:前後加空格 + indexOf */ 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 ) > -1 ) { return true; } } return false; },
jQuery.cssHooks
關於jQuery的鉤子,單獨暴露的一個介面,然使用者可以自定義相容
.toggleClass()
.toggleClass() 負責對匹配元素集中的每個元素增加或刪除一個或多個class,增加或刪除的行為依賴當前元素是否含有指定的class或switch引數的值;
.toggleClass()接受一個或多個class;自從jQuery1.4以後,如果沒有為.toggleClass()指定引數,元素上的所有class名稱將被切換;
自從jQuery1.4以後,className可以是一個函式,函式的返回值作為切換的className。
通過判斷節點上是否有className從而實現切換
結合了hasClass,addClass,removeClass
while ( (className = classNames[ i++ ]) ) { // check each className given, space separated list if ( self.hasClass( className ) ) { self.removeClass( className ); } else { self.addClass( className ); } }