jQuery 2.0.3 源碼分析 鉤子機制 - 屬性操做

jQuery提供了一些快捷函數來對dom對象的屬性進行存取操做. 這一部分仍是比較簡單的.css

根據API這章主要是分解5個方法html

  • .attr()   獲取匹配的元素集合中的第一個元素的屬性的值  或 設置每個匹配元素的一個或多個屬性。
  • .prop() 獲取匹配的元素集中第一個元素的屬性(property)值或設置每個匹配元素的一個或多個屬性。
  • .removeAttr() 爲匹配的元素集合中的每一個元素中移除一個屬性(attribute)。
  • .removeProp() 爲集合中匹配的元素刪除一個屬性(property)。
  • .val() 獲取匹配的元素集合中第一個元素的當前值或設置匹配的元素集合中每一個元素的值

 

jQuery的主要工做仍是爲了解決瀏覽器的兼容性. 這部分的方法通常都有2個特色.node

  • set方法和get方法一體化. 根據參數數量來判斷是set仍是get.
  • value能夠傳入一個閉包. 這個閉包的返回值纔是真正的value.

 


先看一組HTML結構css3

<input id="Aaron" type="checkbox" checked="checked" />

用attr,與prop取值出input元素上的checkedweb

分別會取得什麼值?api

$('input').attr('checked')  //checked 

$('input').prop('checked')  // true

看到這裏應該知道這兩個方法的區別了。其實從方法名也能夠大體猜出來,.attr()、.prop()分別取的是節點的attribute值、property值。數組

 


attribute和property的區別瀏覽器

attribute:特性閉包

  • 直接寫在標籤上的屬性,能夠經過setAttribute、getAttribute進行設置、讀取

property:屬性dom

  • 經過「.」號來進行設置、讀取的屬性,就跟Javascript裏普通對象屬性的讀取差很少

 

觀察一張圖很直觀的理解:

image

attributes是一個類數組的容器,說得準確點就是NameNodeMap,總之就是一個相似數組但又和數組不太同樣的容器。attributes的每一個數字索引以名值對(name=」value」)的形式存放了一個attribute節點。

attributes是會隨着添加或刪除attribute節點動態更新的。

特性的操做:

  • getAttribute
  • setAttribute
  • removeAttribute

property就是一個屬性,若是把DOM元素當作是一個普通的Object對象,那麼property就是一個以名值對(name=」value」)的形式存放在Object中的屬性。要添加和刪除property也簡單多了,和普通的對象沒啥分別。

之因此attribute和property容易混倄在一塊兒的緣由是,不少attribute節點還有一個相對應的property屬性

DOM元素一些默認常見的attribute節點都有與之對應的property屬性,比較特殊的是一些值爲Boolean類型的property,如一些表單元素。

總的來講:基本能夠總結爲attribute節點都是在HTML代碼中可見的,而property只是一個普通的名值對屬性

 


  • jQuery.prototype.attr
  • jQuery.prototype.prop
  • jQuery.prototype.removeAttr
  • jQuery.prototype.removeProp
  • jQuery.prototype.val

jQuery把又長又難記的函數用外觀模式包裝成attr,prop,內部setAttribute,getAttribute是低級API,實現核心功能, 從而隱藏了用戶程序對jQuery各個模塊調用的複雜性

看看源碼的實現

attr: function( ele, value ) {
        return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
    },
prop: function( name, value ) {
        return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
    },

暴露給api的原型方法很是簡單,只有一句話.把參數交給jQuery.access函數去處理. jQuery.access主要做用是修正參數.

access函數裏的第二個參數jQuery.attr. 這個參數的做用是告訴access方法, 修正完參數後再去調用 jQuery.attr方法.

access方法是能夠被抽象出複用的一組對參數的修正方法,經過分解成單一的數據後,而後調用傳遞的回調處理鉤子 好比 attr,css, prop.等等

 

jQuery.access源碼

access源碼部分比較簡單, 就是對象傳參分解成單一的參數從而set,get處理

 


關於jQuery Hooks 

你知道一些核心jQuery函數都有本身的「插件API」稱爲「鉤子」?

詳見:http://blog.rodneyrehm.de/archives/11-jQuery-Hooks.html

大概意思以下:

jQuery提供一個API來調用用戶自定義的函數,用於擴展,以便獲取和設置特定屬性值

主要是:.attr(), .prop(), .val() and .css()四種類型的處理

鉤子都有類似的結構

var someHook = {
    get: function(elem) {
        // obtain and return a value
        return "something";
    },
    set: function(elem, value) {
        // do something with value
    }
}

 

 


如何使用?

用jQuery官方提供的爲列 http://www.css88.com/jqapi-1.9/jQuery.cssHooks/

在作css3屬性瀏覽器兼容的時候,都須要特定的前綴

Webkit的瀏覽器:-webkit-border-radius

Firefox:-moz-border-radius

此時我看能夠採用一個CSS hook 能夠標準化這些供應商前綴的屬性,讓.css() 接受一個單一的,標準的屬性的名稱(border-radius,或用DOM屬性的語法,borderRadius

判斷的代碼省略,直接看實現

給某一元素設置borderRadius,爲10px

$("#element").css("borderRadius", "10px");

爲了作瀏覽器兼容,咱們不得不

if(webkit){
   ........................
}else if(firefox){
  ............................
}else if(...)更多

這是一種最沒技術含量的寫法了,若是咱們換成一種hook的話

$.cssHooks.borderRadius = {
      get: function( elem, computed, extra ) {
        return $.css( elem, borderRadius );
      },
      set: function( elem, value) {
        elem.style[ borderRadius ] = value;
      }
    };

borderRadius = styleSupport( "borderRadius" ); //獲取到相對應的瀏覽器標準

這裏可能還不直觀的體現,咱們深刻到attr源碼中看看

 


jQuery.attr 靜態方法

jQuery實例的方法都是調用最終的靜態方法:jQuery.attr

access函數最後把參數又傳遞給了jQuery.attr, 在jQuery.attr裏才真正進行setAttribute/getAttribute操做.

 

查看源碼關於attrHooks一個type

意思就是在使用attr(‘type’,??)設置的時候就會調用這個hooks,用於處理IE6-9 input屬性不可寫入的問題

attrHooks: {
            type: {
                set: function( elem, value ) {
                    if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
                        // Setting the type on a radio button after the value resets the value in IE6-9
                        // Reset value to default in case type is set after value during creation
                        var val = elem.value;
                        elem.setAttribute( "type", value );
                        if ( val ) {
                            elem.value = val;
                        }
                        return value;
                    }
                }
            }
        },

 

省略部分代碼attr源碼

image

 

  • 經過hooks = jQuery.attrHooks[ name ]方法,去適配對應的name,是否在合集中
  • 若是是hooks而後又是get方法就調用 hooks && "set" in hooks && (ret = hooks.set( elem, value, name )
  • 若是有ret返回值就return(hooks.set可能還不是最終匹配)
  • 不然繼續往下走

 

其實這樣的思路,在sizzle選擇器也大量的運用了

鉤子就是適配器原理,用來處理一些特殊的屬性,樣式或事件。而這些屬性,樣式或事件,咱們能夠經過瀏覽器的特徵嗅探,把相應的解決方法添加到適配器中。有了這些適配器,jQuery就能夠省去許多if else 斷定


那麼,利用鉤子處理兼容與擴展的好處:

  • 適配器這種模式對於擴展新功能很是有利
  • 若是採用鉤子處理的話,咱們就省去了一大堆if else的分支判斷
  • 因爲JS用對象作爲表進行查找是比if條句與switch語句快不少

 

本章的重點在於如何靈活運用運用鉤子的原理,在實際項目中更好的處理兼容與擴展

相關文章
相關標籤/搜索