屬性操做javascript
1.6.1相對1.5.x最大的改進,莫過於對屬性.attr()的重寫了。在1.6.1中,將.attr()一分爲二: .attr()、.prop(),這是一個使人困惑的變動,也是一個破壞性的升級,會直接影響到無數的網站和項目升級到1.6。css
簡單的說,.attr()是經過setAttribute、getAttribute實現,.prop()則經過Element[ name ]實現:html
jQuery.attrjava |
setAttribute, getAttributenode |
jQuery.removeAttrjquery |
removeAttribute, removeAttributeNode(getAttributeNode )數組 |
jQuery.prop瀏覽器 |
Element[ name ]函數 |
jQuery.removeProp工具 |
delete Element[ name ] |
事實上.attr()和.prop()的不一樣,是HTML屬性(HTML attributes)和DOM屬性(DOM properties)的不一樣。HTML屬性解析的是HTML代碼中的存在的屬性,返回的老是字符串,而DOM屬性解析的是DOM對象的屬性,多是字符串,也多是一個對象,可能與HTML屬性相同,也可能不一樣。
1 <a href="abc.html" class="csstest" style="font-size: 30px;">link</a> 2 3 <input type="text" value="123"> 4 5 <input type="checkbox" checked="checked">
javascript代碼:
1 console.info( $('#a').attr('href') ); // abc.html 2 3 console.info( $('#a').prop('href') ); // file:///H:/open/ws-nuysoft/com.jquery/jquery/abc.html 4 5 6 console.info( $('#a').attr('class') ); // csstest 7 console.info( $('#a').prop('class') ); // csstest 8 9 console.info( document.getElementById('a').getAttribute('class') ); // csstest 10 11 console.info( document.getElementById('a').className ); // csstest 12 13 console.info( $('#a').attr('style') ); // font-size: 30px; 14 15 console.info( $('#a').prop('style') ); // CSSStyleDeclaration { 0="font-size", fontSize="30px", ...} 16 17 console.info( document.getElementById('a').getAttribute('style') ); // font-size: 30px; 18 19 console.info( document.getElementById('a').style ); // CSSStyleDeclaration { 0="font-size", fontSize="30px", ...} 20 21 console.info( $('#text').attr('value') ); // 123 22 console.info( $('#text').prop('value') ); // 123 23 24 console.info( $('#checkbox').attr('checked') ); // checked 25 console.info( $('#checkbox').prop('checked') ); // true 26 27
不一樣之處總結以下:
1.屬性名可能不一樣,儘管大部分的屬性名仍是類似或一致的。
2.HTML屬性值老是返回字符串,DOM屬性值則多是整型、字符串、對象,能夠獲取更多的內容
3.DOM屬性老是返回當前的狀態(值),而HTML屬性(在大多數瀏覽)返回的初始化時的狀態(值)
4.DOM屬性只能返回固定屬性名的值,而HTML屬性則能夠返回在HTML代碼中自定義的屬性名的值
5.相對於HTML屬性的瀏覽器兼容問題,DOM屬性名和屬性值在瀏覽器之間的差別更小,而且DOM屬性也有標準可依
優先使用.prop(),由於.prop()老是返回最新的狀態(值)
從源碼能夠看出.attr()的處理過程,先特殊處理各類特殊狀況,再用約定getAttribute()和setAttribute()方法
jQuery.attr()源碼:
.attr(attributeName) 取得第一個匹配元素的屬性值(當屬性沒有被設置時,返回undefined,不能用在文本節點、註釋節點、屬性節點上)
.attr(attributeName, value) 設置單個屬性
.attr(map) 設置多個屬性
.attr(attributeName, function(index, attr)) 經過函數的返回值設置屬
1 //工具方法 設置或獲取HTML元素 setAttribute和getAttribute實現 2 attr: function( elem, name, value, pass ) { 3 var nType = elem.nodeType; 4 //節點類型不能是:文本 註釋 屬性節點 5 if(!elem || nType === 3 || nType === 8 nType === 2){ 6 return undefined; 7 } 8 //1>>遇到與方法同名的屬性 則執行方法 9 //2>>遇到擴展或須要修正的屬性 執行相應的方法 10 //判斷屬性名是否在jQuery提供的方法jQuery.attrFn中,是則直接調用方法。 11 if(pass && name in jQuery.attrFn){//屬性方法 12 return jQuery(elem)[name](value); 13 } 14 //若是不支持getAttribute 則調用$.prop()方法 15 if(!("getAttribute" in elem)){ 16 return jQuery.prop(elem,name,value); 17 } 18 var ret,hooks, 19 notxml = nType !==1 || !jQuery.isXMLDoc(elem);//判斷documentElement是否存在 20 21 //格式化name attrFix: { tabindex: "tabIndex"} 22 name = notxml && jQuery.attrFix[name] || name; 23 //屬性鉤子:type: tabIndex 24 hooks = jQuery.attrHooks[name]; 25 //若是沒有name對應的鉤子 26 if(!hooks){ 27 //使用boolean鉤子處理boolean屬性 28 (typeof value === "boolean" || value === undefined || value.tolowerCase() === name.toLowerCase())){ 29 //使用布爾鉤子(靜態方法對象):set get 30 hooks = boolHook; 31 //使用表單鉤子 32 }else if (formHook && (jQuery.nodeName(elem,"form") || rinvalidChar.test(name))){ 33 //使用表單鉤子(靜態方法對象):set get 34 hooks = formHook; 35 } 36 } 37 38 //定義了value 設置或刪除 39 if(value !== undefined){ 40 /* 41 typeof null === 'object' true 42 typeof undefined === 'undefined' true 43 null == undefined true 44 null === undefined false 45 */ 46 if(value === null){//有值可是爲空 即將值設置爲空 47 jQuery.reomveAttr(elem,name); 48 return undefined; 49 //屬性鉤子 布爾鉤子 表單鉤子 若是有對象的鉤子 就調用set方法 50 }else if(hooks && "set" in hooks && noxml && (ret = hooks.set(elem,value,name))!==undefeind){ 51 return ret; 52 }else{ 53 //調用setAttribute方法 54 elem.setAttribute(name,"" + value); 55 return value; 56 } 57 //value是undefined,說明去屬性 ,存在對應鉤子有get方法,調用鉤子的get方法 58 }else if(hooks && "get" in hooks && notxml){ 59 return hooks.get(elem,name); 60 }else{ 61 //取屬性值 62 ret = elem.getAttribute(name); 63 //屬性不存返回null 格式化爲undefined 64 return ret === null ? undefined : ret; 65 } 66 },
其中調用的鉤子有些不明白的地方:
attrHooks源碼:若是name = type屬性,則加判斷後調用setAttribute設置屬性值,或者name = tabIndex時經過getAttributeNode("tabIndex")得到//得到自定義對象屬性.
//屬性鉤子 name = type || tabIndex attrHooks: { type: { set: function( elem, value ) { //type屬性在IE下不能改變 若是改變報錯 if ( rtype.test( elem.nodeName ) && elem.parentNode ) { jQuery.error( "type property can't be changed" ); } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { var val = elem.value; elem.setAttribute( "type", value );//最後調用setAttribute設置type屬性的值 if ( val ) { elem.value = val; } return value; } } }, tabIndex: { get: function( elem ) { //得到tabIndex的值 var attributeNode = elem.getAttributeNode("tabIndex");//得到自定義對象屬性 return attributeNode && attributeNode.specified ? parseInt( attributeNode.value, 10 ) ://得到自定義對象屬性的值 rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 0 : undefined; } } },
AttrFn源碼:若是name在這個屬性方法的對象中,直接調用這個屬性方法。
//取屬性用到的方法 attrFn: { val: true, css: true, html: true, text: true, data: true, width: true, height: true, offset: true },
boolHook源碼:
1 //bool鉤子 2 boolHook = { 3 get: function( elem, name ) { 4 // Align boolean attributes with corresponding properties 5 return elem[ jQuery.propFix[ name ] || name ] ? 6 name.toLowerCase() : 7 undefined; 8 }, 9 set: function( elem, value, name ) { 10 var propName; 11 if ( value === false ) {//value不存在時,刪除boolean屬性 12 jQuery.removeAttr( elem, name ); 13 } else { 14 //屬性名 是否在propFix中,存在就直接調用 15 propName = jQuery.propFix[ name ] || name; 16 if ( propName in elem ) { 17 elem[ propName ] = value; 18 } 19 //propName不在elem中就用setAttribute 20 elem.setAttribute( name, name.toLowerCase() ); 21 } 22 return name; 23 } 24 };
formHook源碼:設置表單鉤子,get/set。
$.prop()源碼:
1 //獲取DOM屬性 2 prop: function( elem, name, value ) { 3 var nType = elem.nodeType; 4 //節點類型不能是:文本 註釋 屬性節點 5 if(!elem || nType === 3 || nType === 8 nType === 2){ 6 return undefined; 7 } 8 var ret,hooks, 9 notxml = nType !==1 || !jQuery.isXMLDoc(elem);//判斷documentElement是否存在 10 11 //格式化name attrFix: { tabindex: "tabIndex"} 12 name = notxml && jQuery.attrFix[name] || name; 13 //屬性鉤子:name = type || tabIndex 14 hooks = jQuery.attrHooks[name]; 15 if(value !== undefined){ 16 //若是鉤子存在set 調用set方法 17 if(hooks && "set" && (ret = hooks.set(elem,value,name))!==undefined){ 18 return ret; 19 }else{ 20 return (elem[name] = value); 21 } 22 //讀取 23 }else{ 24 if(hooks && "get" && (ret = hooks.get(elem,value,name))!==undefined){ 25 return ret; 26 }else{ 27 return elem[name]; 28 } 29 } 30 },
jQuery中調用access方法實現jQuery.fn.attr和jQuery.fn.prop:
1 attr: function( name, value ) { 2 return jQuery.access( this, name, value, true, jQuery.attr ); 3 }, 4 5 prop: function( name, value ) { 6 return jQuery.access( this, name, value, true, jQuery.prop ); 7 }
$.access方法源碼:
多功能函數:讀取或設置集合的屬性值;值爲函數時會被執行
1>>elems:元素的集合,【collection】【類】數組
2>>key:屬性名稱,key的只爲object時,會拆解key爲key,value形式再次執行jQuery.access
3>>value:屬性值
4>>exec:在屬性值爲function時是否對設置以前的value值執行函數(這裏爲true)
5>>fn:執行的函數
6>>pass:是否設置爲jQuery對象的屬性 attr時使用
用於fn:jQuery.fn.css(),jQuery.fn.attr(),jQueyr.fn.prop
return jQuery.access( this, name, value, true, function( elem, name, value ) {});
說明:主要用於參數的循環處理,爲何要這樣作?待詳細分析
access:function(elems,key,value,exec,fn,pass){ var elems = elems.length; //若是有多個屬性就迭代 if(typeof key === "object"){ for(var k in key){//key的參數循環處理 jQuery.access(elems,k,key[k],exec,fn,value); } return elems; } //只設置一個屬性 if(value !== undefined){ exec = !pass && exec && jQuery.isFunction(value); for (var i=0;i<length;i++){ fn(elems[i],key, exec ? value.call(elems[i],i,fn(elems[i],key)) : value,pass); } return elems; } //讀取屬性 return length ? fn(elems[0],key) : undefined; },