jQuery屬性操作之.attr()
目錄
轉載請註明出處
@
.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()靜態方法的原始碼定義,用同樣的簡化方法分析,得到:
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元素的指定屬性的值.
由jQuery.access簡化程式碼中的return jQuery.attr( this[0], name );
可知,只傳入一個name引數的情況下,確實只會返回jQuery物件中的索引為'0'的DOM物件的指定屬性的屬性值.
呼叫形式:$("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的兩個引數雖然有規定,但是不需要我們真的傳參,而是函式體內部使用索引值或者當前屬性值的一個介面]