jQuery 源碼分析(十二) 數據操做模塊 html特性 詳解

jQuery的屬性操做模塊總共有4個部分,本篇說一下第1個部分:HTML特性部分,html特性部分是對原生方法getAttribute()和setAttribute()的封裝,用於修改DOM元素的特性的css

jQuery的靜態方法含有以下API:html

  • $.attr(elem, name, value)  ;設置或讀取html屬性,該方法有三種用法:

                    ·$.attr(elem,name,null)       ;若是value爲null則調用jQuery.removeAttr(elem, name)刪除該屬性
                    ·$.attr(elem,name,value)    ;設置elem元素的name屬性值爲value。
                    ·$.attr(elem,name)              ;獲取elem元素的name屬性node

  • $.removeAttr(elem, name)  ;從DOM元素elem上移除name屬性,name能夠是單個字符串,也能夠是空格分隔的多個html屬性。對於應布爾屬性會同步設置對應的DOM屬性爲false。

jQuery/$ 實例方法(能夠經過jQuery實例調用的):jquery

  • attr(name, value)           ;移除、設置html屬性,有如下方法

      ·attr(obj)             ;參數1是對象時                             ;access()函數中驗證 表示一次性設置多個屬性
      ·attr(name,value)       ;爲每一個匹配元素設置一個HTML屬性                  ;value能夠是一個函數,取值爲返回值,也能夠爲null時表示刪除該屬性    
      ·attr(name,NULL)         ;參數2爲NULL時表示刪除全部匹配元素的name特性,間接調用removeAttr()
      ·attr(name)              ;參數1是字符串時,參數2未指定或者設置爲false    ;表示獲取第一個匹配元素的HTML屬性值。數組

  • removeAttr(name)                    ;移除每個匹配元素的一個或多個HTML屬性,name是要是移除的html屬性,多個能夠用空格分隔

舉個栗子:瀏覽器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
</head>
<body>
    <a>連接</a>
    <button>淘寶</button>                <!--點擊後a標籤將導航到淘寶-->
    <button>百度</button>                <!--點擊後a標籤將導航到百度-->
    <button>移除</button>                <!--點擊後a標籤將取消導航-->
    <script>
        let a      = document.getElementsByTagName('a')[0],                //獲取a標籤的引用
            b1    = document.getElementsByTagName('button')[0],            //淘寶按鈕的引用
            b2    = document.getElementsByTagName('button')[1],            //百度按鈕的引用
            b3    = document.getElementsByTagName('button')[2];            //移除按鈕的引用
        b1.addEventListener('click',function(){
            $.attr(a,'href','http://www.taobao.com');            //經過jQuery的靜態方法設置href屬性
        })
        b2.addEventListener('click',function(){
            $('a').attr('href','http://www.baidu.com')            //經過jQuery的實例方法設置href屬性
        })
        b3.addEventListener('click',function(){
            $("a").removeAttr('href')                            //移除href屬性
        })
    </script>    
</body>
</html>

渲染的頁面以下:app

 此時對應的DOM結構以下:函數

  當咱們點擊淘寶按鈕後頁面變爲了以下:工具

DOM修改了這樣子:源碼分析

此時點擊這個a標籤將連接到淘寶網,而後咱們點擊百度,連接會連接到百度去的,最後點擊移除時,該a標籤又會變爲初始化的狀態。這就是jQuery的html特性操做

 

源碼分析


 $.attr和$.removeAttr實現以下:

jQuery.extend({
    attr: function( elem, name, value, pass ) {            //設置或讀取html屬性,是對原生方法getAttribute()和setAttribute()的簡化
        var ret, hooks, notxml,
            nType = elem.nodeType;

        // don't get/set attributes on text, comment and attribute nodes
        if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {        //若是elem爲空 或者是文本、註釋、屬性節點
            return;                                                            //直接返回,不接着處理
        }

        if ( pass && name in jQuery.attrFn ) {
            return jQuery( elem )[ name ]( value );
        }

        // Fallback to prop when attributes are not supported
        if ( typeof elem.getAttribute === "undefined" ) {                //若是不支持方法getAttribute
            return jQuery.prop( elem, name, value );                        //則調用對應的DOM屬性
        }

        notxml = nType !== 1 || !jQuery.isXMLDoc( elem );                //判斷elem是否不是xml文檔元素

        // All attributes are lowercase
        // Grab necessary hook if one is defined
        if ( notxml ) {
            name = name.toLowerCase();
            hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
        }

        if ( value !== undefined ) {                                    //若是傳入了參數value,表示是設置值

            if ( value === null ) {                                            //值是null,則移除該name屬性
                jQuery.removeAttr( elem, name );
                return;

            } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {    //優先調用對應的修正對象的修正方法set()
                return ret;

            } else {
                elem.setAttribute( name, "" + value );                    //不然調用原生方法setAttribute()設置html屬性
                return value;
            }

        } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {    //若是未傳入參數value,優先調用對應的修正對象的修正方法get()
            return ret;

        } else {

            ret = elem.getAttribute( name );                            //不然調用原生方法getAttrubute()讀取html屬性。

            // Non-existent attributes return null, we normalize to undefined
            return ret === null ?
                undefined :
                ret;
        }
    },

    removeAttr: function( elem, value ) {                    //從DOM元素上移除一個或多個html屬性,多個html屬性用空格分隔。是對removeAttribute的封裝和擴展。
        var propName, attrNames, name, l,
            i = 0;

        if ( value && elem.nodeType === 1 ) {                    //若是設置了value參數 且 elem是一個元素節點
            attrNames = value.toLowerCase().split( rspace );        //執行後attrNames是一個數組,保存了要移除的屬性名:好比:Array [ "id", "name" ] rspace = /\s+/,    
            l = attrNames.length;                                    //須要移除的屬性的個數

            for ( ; i < l; i++ ) {                                    //遍歷數組attrNames,逐個移除html屬性。
                name = attrNames[ i ];                                    //name是要移除的屬性名

                if ( name ) {
                    propName = jQuery.propFix[ name ] || name;                    //若是屬性名name須要修正,則修正屬性

                    // See #9699 for explanation of this approach (setting first, then removal)
                    jQuery.attr( elem, name, "" );                                //先將html屬性設置爲空字符串,以解決Webkit內核瀏覽器不能
                    elem.removeAttribute( getSetAttribute ? name : propName );    //調用原生方法removeAttribute刪除對應的屬性,若是jQuery.support.getSetAttribute爲true則刪除name屬性,若是爲false,表示在IE六、7下則刪除特殊屬性。

                    // Set corresponding property to false for boolean attributes
                    if ( rboolean.test( name ) && propName in elem ) {            //對應布爾屬性,同步設置對應的DOM屬性爲false
                        elem[ propName ] = false;
                    }
                }
            }
        }
    },
    /**/
})

對於jQuery實例來講,它調用了不一樣的工具函數,最後仍是執行上面講解的靜態方法的,以下:

jQuery.fn.extend({
    attr: function( name, value ) {            //移除、設置html屬性
        return jQuery.access( this, name, value, true, jQuery.attr );    //調用了jQuery.access工具函數,參數5傳入了jQuery.attr
    },

    removeAttr: function( name ) {            //移除html屬性
        return this.each(function() {            //經過each函數方法,依次執行jQuery.removeAttr()
            jQuery.removeAttr( this, name );
        });
    },
    /**/
})

因爲jQuery中的特性、DOM屬性和樣式操做的函數參數能夠是差很少的,jQuery就定義了一個access函數,爲.attr()、.prop()、.css()提供支持,這樣咱們經過jQuery實例設置特性、屬性和樣式時能夠傳入的參數類型,例如:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script>
</head>
<body>
    <a>連接</a>
    <script>
        $('a').attr('href','http://www.cnblogs.com')            //參數2是個字符串
        $('a').attr('href',()=>'http://www.cnblogs.com')        //參數2仍是是個函數
        $('a').attr({href:'http://www.cnblogs.com'})            //也能夠傳入一個對象        
    </script>    
</body>
</html>

咱們傳入不一樣的參數,均可以實現設置特性的效果,這就是$.access的做用,$.access的源碼實現以下:

jQuery.extend({                
    access: function( elems, key, value, exec, fn, pass ) {        //爲集合中的元素設置一個或多個屬性值,或者讀取第一個元素的屬性值
        var length = elems.length;

        // Setting many attributes
        if ( typeof key === "object" ) {                            //若是key是對象,表示要設置多個屬性,則遍歷該對象循環執行.access函數
            for ( var k in key ) {
                jQuery.access( elems, k, key[k], exec, fn, value );
            }
            return elems;
        }

        // Setting one attributes
        if ( value !== undefined ) {                                //若是參數value不是undefined,表示要設置單個屬性
            // Optionally, function values get executed if exec is true
            exec = !pass && exec && jQuery.isFunction(value);            //修正exec參數。若是沒有傳入pass參數或者該參數值是false,且參數exec爲true,且value是函數則設置exec爲true,不然exec爲false。

            for ( var i = 0; i < length; i++ ) {
                fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );        //遍歷元素集合elems,爲每一個元素調用回調函數fn
            }

            return elems;                                                //遍歷完成後返回元素elems。以支持鏈式操做
        }

        // Getting an attribute
        return length ? fn( elems[0], key ) : undefined;            //當value參數爲空,且元素集合elems不爲空則獲取第一個匹配元素相關的信息,即執行fn函數
    },
    /**/
})

 writer by:大沙漠 QQ:22969969

以後的DOM屬性和樣式操做都會借用access這個工具方法的。

相關文章
相關標籤/搜索