轉載請註明出處 @[toc] .attr() 1. .attr() 的四種用法 大致用法: 調用形式:$("xxx").attr(attrName); 獲取匹配到的所有元素中的第一個元素的指定屬性的屬性值. 調用形式:$("xxx").attr(attrName,value): 設置/新增匹配到的所 ...
目錄
轉載請註明出處
@
.attr()
1..attr()的四種用法
大致用法:
- 調用形式:$("xxx").attr(attrName);
獲取匹配到的所有元素中的第一個元素的指定屬性的屬性值.
- 調用形式:$("xxx").attr(attrName,value):
- 設置/新增匹配到的所有元素的指定屬性的屬性值
- 如果value=null,指定屬性將被刪除
- 設置/新增匹配到的所有元素的指定屬性的屬性值
- 調用形式:$("xxx").attr(attrObject):
用"屬性-值"的鍵值對構成的對象來設置匹配到的所有元素的一個或多個屬性.
- 調用形式:$("xxx").attr(attrName,attrFn(index,val)):
用一個函數attrFn的返回值作為value來設置某一個匹配元素的指定屬性.(attrFn函數的參數有明確規定:index--該匹配元素在jQuery對象中的index值,也就是它的鍵值.attr--當前該元素的該屬性的值(舊值))
用法詳解:
(1)..attr()源代碼定義:
jQuery.fn.extend( {
attr: function( name, value ) {
return access( this, jQuery.attr, name, value, arguments.length > 1 );
}
}
可見,.attr的核心是函數access(),而該函數不需要實例即可調用,屬於直接定義在jQuery上的'靜態函數'.
jQuery.access()源代碼定義:
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
var i = 0,
length = elems.length,
bulk = key == null; //bulk用於判斷key值是否為null(註:null==undefined的結果為true)
// 設置多個值(當key參數為對象時,註:jQuery.type實現原理是[[class]])
if ( jQuery.type( key ) === "object" ) {
chainable = true;
for ( i in key ) {
access( elems, fn, i, key[ i ], true, emptyGet, raw );
}
// 設置一個值(當key為非對象類型時)
} else if ( value !== undefined ) {
chainable = true;
if ( !jQuery.isFunction( value ) ) {
raw = true; //判斷value值是否為函數類型.如果不是函數,設置raw值,為if(fn)以及if(bulk)埋下伏筆
}
if ( bulk ) { //當傳入key值為null時的處理情況(這段代碼,我們在分析.attr()時不會用到)
// Bulk operations run against the entire set
if ( raw ) {
fn.call( elems, value );
fn = null;
// ...except when executing function values
} else {
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
};
}
}
if ( fn ) { //對elems中的每一個元素應用fn方法,第三個參數由raw決定
for ( ; i < length; i++ ) {
fn(
elems[ i ],
key,
raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) )
);
}
}
}
return chainable ? //返回值設定
elems :
// Gets
bulk ?
fn.call( elems ) :
length ? fn( elems[ 0 ], key ) : emptyGet;
}
如上圖,由於access函數用途並不局限於我們的.attr(),作為像筆者一樣的jQuery初學者,源代碼中有許多代碼語句我們不能很好的理解(比如:if(bulk)部分).由於暫時接觸到的jQuery內容較少較淺,我們如果一味深究,可能既搞不清楚原理,還浪費時間.所以,我們可以用一種簡化的思想來分析問題: 只關註代碼中跟我們當前問題有關的部分,忽略無關的,用不到的部分.
具體做法:我們將.attr()的四種用法的實際傳參情況帶入jQuery.access函數的定義中,刪除我們進不去的if語句代碼塊,只保留會用到的代碼語句.
調用形式:$("xxx").attr(name)
attr定義:
attr: function( name, value=undefined ) {
return jQuery.access( this, jQuery.attr, name, value=undefined, arguments.length > 1 );
}
access調用簡化:
var access = function( this, jQuery.attr, name, value=undefined, chainable=false, emptyGet=undefined, raw=undefined ) {
var i = 0,
length = this.length, //jQuery對象的length屬性(jQuery對象總是有length屬性,它是類數組對象)
bulk = false;
return jQuery.attr( this[0], name );
};
同樣,我們找到jQuery.attr()靜態方法的源代碼定義,用同樣的簡化方法分析,得到:
jQuery.attr()完整源碼:
attr: function( elem, name, value ) { // elem:DOM對象 name:屬性名/鍵名 value:屬性值
var ret, hooks,
nType = elem.nodeType; // 節點類型
// 屏蔽屬性節點,文本節點與註釋節點
if ( nType === 3 || nType === 8 || nType === 2 ) {
return;
}
// 當屬性不支持getAttribute方法時,回調jQuery.prop()方法--從操作attribute變成了操作property
if ( typeof elem.getAttribute === "undefined" ) {
return jQuery.prop( elem, name, value );
}
//下麵的都是DOM元素elem支持getAttribute的情況
// 所有標簽特性(attributes)都是小寫(處理相容:有的瀏覽器對同一屬性的名稱可能大小寫不停)
// 如果某一個是已定義的,抓取必要的鉤子
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { // 非元素節點或者是XML文本中的元素
name = name.toLowerCase();
hooks = jQuery.attrHooks[ name ] ||
( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
}
if ( value !== undefined ) {//如果value在傳參時未被忽略
if ( value === null ) {
jQuery.removeAttr( elem, name );//傳入第三個參數為null時,調用jQuery.removeAttr移除對應屬性
return;
}
if ( hooks && "set" in hooks &&
( ret = hooks.set( elem, value, name ) ) !== undefined ) {
return ret;
}
elem.setAttribute( name, value + "" );
return value;
}
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
return ret;
}
ret = jQuery.find.attr( elem, name );
// 不存在的屬性會返回null,我們將之統一為undefined
return ret == null ? undefined : ret;
}
jQuery.attr()簡化:
attr: function( elem, name, value=undefined ) { // elem:DOM對象 name:屬性名/鍵名 value:屬性值
var ret, hooks,
nType = 1;
ret = jQuery.find.attr( elem, name );
return ret;
}
其中,唯一不確定的是jQuery.find.attr,然而我們繼續找下去則是有關Sizzle選擇器引擎的問題,這對於我們初學者來說過於複雜.因此,我們再簡化一下,帶入實際情景,檢測這一函數的輸出:
var $p = $('#jQueryTest')[0];
console.log(jQuery.find.attr($p,'id')); //jQueryTest
因此,大概知道該函數該種傳參情況下的作用是返回指定DOM元素的指定屬性的值.
1.由jQuery.access簡化代碼中的return jQuery.attr( this[0], name );
可知,只傳入一個name參數的情況下,確實只會返回jQuery對象中的索引為'0'的DOM對象的指定屬性的屬性值.
2.由jQuery.att()完整代碼中
if ( typeof elem.getAttribute === "undefined" ) {
return jQuery.prop( elem, name, value );
}
可知:如果不支持get/setAttibute,那麼原來的針對特性(attibute)的操作就會變成DOM元素屬性(property)的操作.
調用形式:$("xxx").attr(name,value);
attr定義:
attr: function( name, value) { //此時的this是一個類數組
return jQuery.access( this, fn=jQuery.attr, name, value, chainable=true);
}
access調用簡化:
var access = function( this, jQuery.attr, name, value, chainable=true, emptyGet=undefined, raw=undefined ) {
var i = 0,
length = this.length, //jQuery對象的length屬性,表示找到的匹配的DOM元素的個數
bulk = false;
chainable = true;
if ( !jQuery.isFunction( value ) ) { //當value值不為函數時,設置raw為true,這是為了下一步if(jQuery.attr)中的raw判斷做鋪墊
raw = true;
}
if ( jQuery.attr ) { //jQuery.attr,為true
for ( ; i < length; i++ ) { //用for迴圈是因為此時的this是一個包含多個DOM元素的jQuery對象
jQuery.attr(
this[ i ],
name,
raw ? value : value.call( elems[ i ], i, jQuery.attr( this[ i ], name ) )
);//raw為true,也就是value不為函數時,用value作第三參數
}
}
}
return this; //返回jQuery對象本身
};
而,我們用簡化的方法分析此種情況下的jQuery.attr(this,name,value):
attr: function( this[i], name, value ) {
var ret, hooks,
nType = this[i].nodeType;
if ( value !== undefined ) { //判斷為true,進入if語句
if ( value === null ) {
jQuery.removeAttr( this[i], name );//如果value為null,刪除該jQuery對象的所有匹配元素的指定屬性
return;
}
this[i].setAttribute( name, value + "" );//設置當前DOM元素的指定屬性的屬性值
return value;
}
ret = jQuery.find.attr( this[i], name ); //刪除了屬性,返回null;否則,返回指定屬性的屬性值
return ret == null ? undefined : ret; //如果刪除了指定屬性,返回undefined;如果修改了屬性,返回指定屬性值
}
調用形式:$("xxx").attr(attrObject);
attr定義:
attr: function( name=attrObject ) {
return jQuery.access( this, jQuery.attr, name=attrObject, value=undefined, false);
}
access調用簡化:
var access = function( this, fn, name, value=undefined, chainable=false, emptyGet=undefined, raw=undefined ) {
var i = 0,
length = this.length, //元素的length屬性
bulk = false;
// 設置多個value值
if ( jQuery.type( name ) === "object" ) { //如果傳入的name形參為對象類型
chainable = true;
for ( i in name ) { //對每一個對象中的屬性名及屬性值再次調用本身(遞歸)
access( this, fn, i, name[ i ], true, emptyGet, raw );
}
}
return elems; //返回jQuery對象本身
};
可見,對於一個由"屬性-屬性值"鍵值對構成的對象,會對其中的每一個屬性都調用access設置一次.由於代碼中使用的for-in迴圈,所以enumerable為false的鍵值對是無效的.
調用形式:$("xxx").attr(name,attrFn);
attr定義:
attr: function( name, value=attrFn ) {
return jQuery.access( this, jQuery.attr, name, value=attrFn, chainable=true );
}
access調用簡化:
var access = function( this, jQuery.attr, name, value=attrFn, chainable=true, emptyGet=undefined, raw=undefined ) {
var i = 0,
length = this.length, //jQuery對象的length屬性
bulk = false;
chainable = true;
if ( jQuery.attr ) { //true,進入if語句
for ( ; i < length; i++ ) {
jQuery.attr(
this[ i ],
name,
attrFn.call( this[ i ], i, jQuery.attr( this[ i ], name ) ) // 調用attrFn,其返回值作為第三個參數
);
}
}
return elems; // 返回jQuery對象本身
};
由attrFn.call( this[ i ], i, jQuery.attr( this[ i ], name ) )
可知,attrFn的參數限制就是源自這一行代碼:(this[i]是調用attrFn的元素,後面兩個是參數,一個是jQuery對象中的索引值,一個是當前元素的指定屬性name的值的查詢返回)
[特別註意:attrFn的兩個參數雖然有規定,但是不需要我們真的傳參,而是函數體內部使用索引值或者當前屬性值的一個介面]