jQuery attributes(上)


jQuery attributes提供了文檔節點的屬性操作方法。

為了更好的理解,我們先解決jQuery core中的access參數設置函數。

 

jQuery.access

jQuery.access是一個專用於參數設置以及讀取的方法。

jQuery鏈式操作中我們對BigInteger的值獲取是通過方法val來獲取的,很顯然此時val后面不能再鏈式操作了。所以:

如果要讀取參數值,那么這個操作就不能鏈式操作。

/*************************
 *    elems: 接受操作的元素組
 *    fn: 設置或讀取函數
 *    key: 要設置的屬性
 *    value: 要設置的值,也可以是函數
 *    chainable: 是否可以鏈式操作,即是讀還是寫操作
 *    emptyGet: 讀取如果為空用什么表示
 *    raw: value能否直接傳給fn,如果的確就是想將屬性設置成函數value,那么要把這個值設成true
 */
jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
    var i = 0,
        length = elems.length,
        //key是否為空
        bulk = key == null;

    // 設置許多屬性
    if ( jQuery.type( key ) === "object" ) {
        chainable = true;
        for ( i in key ) {
            //迭代執行設置一個值
            jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
        }

    // 只設置一個值
    } else if ( value !== undefined ) {
        chainable = true;

        //如果value不是函數
        if ( !jQuery.isFunction( value ) ) {
            raw = true;
        }

        //如果key為空
        if ( bulk ) {
            // 如果raw為true,即value不是函數
            if ( raw ) {
                //執行fn,其this為elems,參數為value
                fn.call( elems, value );
                fn = null;

            // 如果value是函數
            } else {
                //用bulk保存fn
                bulk = fn;
                //將fn變成特定形式
                fn = function( elem, key, value ) {
                    return bulk.call( jQuery( elem ), value );
                };
            }
        }
        
        //如果fn存在
        if ( fn ) {
            //遍歷所有elems
            for ( ; i < length; i++ ) {
                //value是函數則運行fn(elem, key, value.call(elem, i, fn(elem, key)))
                //value非函數則運行fn(elem, key, value)
                fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
            }
        }
    }

    //如果是可鏈式操作的則返回elems
    return chainable ?
        elems :

        // 否則則是讀取操作
        bulk ?
            fn.call( elems ) :
            // 否則如果長度不為0,則返回fn( elems[0], key ),否則返回空
            length ? fn( elems[0], key ) : emptyGet;
}

jQuery官方文檔沒有該函數,應該說這是jQuery的一個內部工具。主要是為了實現jQuery中設置與讀取復用性邏輯以及其內循環的,也就是為了節省寫代碼而已。

 

jQuery.fn.attr()

fn也就是jQuery實例對象的方法集。

fn中的方法attr也就是我們常用的attr方法。

如獲取em標簽的title屬性:

var title = $("em").attr("title");

那么這個函數式怎么實現的呢?

jQuery.fn.attr = function( name, value ) {
    return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
};

當參數長度為0或只為1時,則是讀取操作,不能鏈式操作。

而這里用的設置函數是jQuery.attr,即實際運行時會運行jQuery.attr(elem, name, value)。

那么jQuery.attr是如何實現的呢?

/***************************
 *    elem: 要操作的元素
 *    name: 元素的屬性名
 *    value: 要改變的值
 */
jQuery.attr = function( elem, name, value ) {
    var ret, hooks, notxml,
        nType = elem.nodeType;

    // 不處理text,comment,attribute節點
    if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
        return;
    }

    // 如果屬性不支持則使用jQuery.prop
    if ( typeof elem.getAttribute === "undefined" ) {
        return jQuery.prop( elem, name, value );
    }

    //是否不是XML
    notxml = nType !== 1 || !jQuery.isXMLDoc( elem );

    // 如果不是XML
    if ( notxml ) {
        //那么所有屬性名應當是小寫
        name = name.toLowerCase();
        //如果屬性定義了,那么就抓住必要的鈎子,解決IE6-9的相關問題
        hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
    }

    //如果value不是沒有定義,即寫入操作
    if ( value !== undefined ) {
        //如果value為空,則是刪除操作
        if ( value === null ) {
            jQuery.removeAttr( elem, name );
        //如果鈎子有set方法,則設置了之后,返回其值
        } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
            return ret;
        //否則使用setAttribute方法
        } else {
            elem.setAttribute( name, value + "" );
            return value;
        }
    //如果是讀取操作,如果鈎子有get方法,則通過get得到返回值
    } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
        return ret;
    //如果沒有get方法
    } else {

        // IE9+中Flash對象沒有.getAttrubute方法,判斷防止錯誤
        if ( typeof elem.getAttribute !== "undefined" ) {
            ret =  elem.getAttribute( name );
        }

        // 返回undefined或則值
        return ret == null ?
            undefined :
            ret;
    }
};

 

jQuery.removeAttr

removeAttr = function( elem, value ) {
    var name, propName,
        i = 0,
        //分解value成為多個屬性的數組
        attrNames = value && value.match( core_rnotwhite );
    
    //如果有要刪除的屬性名
    if ( attrNames && elem.nodeType === 1 ) {
        //遍歷所有屬性名
        while ( (name = attrNames[i++]) ) {
            //看看需不需要用propFix來修改名字,不用直接用name
            propName = jQuery.propFix[ name ] || name;

            // 如果屬性是布爾量先改成false
            if ( rboolean.test( name ) ) {
                elem[ propName ] = false;
            }

            //刪除屬性
            elem.removeAttribute( name );
        }
    }
};

jQuery.propFix干了什么呢?

實際只是修改一下屬性名,比如很多人喜歡用class來表示css類名,但實際上是className。

jQuery.propFix = {
    tabindex: "tabIndex",
    readonly: "readOnly",
    "for": "htmlFor",
    "class": "className",
    maxlength: "maxLength",
    cellspacing: "cellSpacing",
    cellpadding: "cellPadding",
    rowspan: "rowSpan",
    colspan: "colSpan",
    usemap: "useMap",
    frameborder: "frameBorder",
    contenteditable: "contentEditable"
};

 

jQuery.fn.removeAttr

這個函數實現比較簡單,只是用each方法來調用jQuery.removeAttr而已。

jQuery.fn.removeAttr = function( name ) {
    return this.each(function() {
        jQuery.removeAttr( this, name );
    });
};

 

jQuery.fn.prop

jQuery.fn.prop = function( name, value ) {
    return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
};

可見jQuery.fn.prop和jQuery.fn.attr差不多。

 

jQuery.prop

jQuery.prop = function( elem, name, value ) {
    var ret, hooks, notxml,
        nType = elem.nodeType;

    if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
        return;
    }

    notxml = nType !== 1 || !jQuery.isXMLDoc( elem );

    if ( notxml ) {
        // 修復name和鈎子
        name = jQuery.propFix[ name ] || name;
        hooks = jQuery.propHooks[ name ];
    }

    if ( value !== undefined ) {
        if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
            return ret;

        } else {
            return ( elem[ name ] = value );
        }

    } else {
        if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
            return ret;

        } else {
            return elem[ name ];
        }
    }
};

由於和jQuery.attr差不多,就不備注了。

 

jQuery.fn.removeProp

removeProp = function( name ) {
    name = jQuery.propFix[ name ] || name;
    return this.each(function() {
        // try/catch handles cases where IE balks (such as removing a property on window)
        try {
            this[ name ] = undefined;
            delete this[ name ];
        } catch( e ) {}
    });
};

removeProp相對簡單些,只是通過each將所有元素的屬性設為undefined然后delete掉而已。

 

Attrubute和Property

從源代碼我們可以發現,jQuery.attr如果找不到相應的方法會使用jQuery.prop。

jQuery 1.6加入jQuery.prop方法后,對很多人來說可能根本沒啥用,因為用jQuery.attr方法肯定是對的。

但jQuery.attr和jQuery.prop到底差別在哪里呢?

這是Attrubute和Property的差別。

jQuery.attr方法會處理Attrubute和Property,但jQuery.prop只處理Property。

雖然這兩個單詞都可以翻譯成“屬性”,但是這兩個實際上是不同的。

我們用一個例子來說明這個問題:

function Demo(){
    var attrs = {};
    this.name = "Bob";
    this.setAttr = function(name, value){
        attrs[name] = value;
        return value;
    }
    this.getAttr = function(name){
        return attrs[name];
    }
}

那么對於一個實例:

var i = new Demo();
i.name    //Property
i.setAttr("name", "Tom");
i.getAttr("name")    //Attrubute

所以jQuery文檔中對jQuery.prop的解釋是:獲取在匹配的元素集中的第一個元素的屬性值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM