有人給 Multiple Select 外掛程式 提了問題:
setSelects doesn't work in Firefox when using jquery 1.9.0 一直都在用 jQuery 1.8.3 的版本,沒有嘗試過 jQuery 1.9.0 的版本。
於是,開始調試程式碼,在1.9.0 的版本:
<input type="checkbox" /> <script> $(function() { $('input').click(function() { $(this).attr('checked'); }); }); </script>
點擊checkbox,結果都是undefined
而在1.8.3 的版本中,結果是checked 和undefined
到這裡,問題答案找到了,就是使用attr() 方法的問題,於是查看官方文檔, 才知道從jQuery 1.6 開始新增了一個方法prop(),但是一直都沒有使用過。
從中文意思看,兩者分別是取得/設定 attributes 和 properties 的方法,那麼為什麼還要增加 prop() 方法呢?
Before jQuery 1.6, the .attr() method sometimes took property values into account when retrieving some attributes, which could cause inconsistent behavior.
因為在 jQuery 1.6 之前,使用 attr() 有時候會出現不一致的行為。
那麼,什麼時候使用attr(),什麼時候使用prop()?
To retrieve and change DOM properties such as the checked, selected, or disabled state of form elements, use the .prop() method.
根據官方的建議:具有true 和false 兩個屬性的屬性,如checked, selected 或disabled 使用prop(),其他的使用attr()
到此,將attr('checked') 改成prop('checked') 即可修復提的issues 了。
等等,看似問題還沒真正解決,為什麼開頭範例中 jQuery 1.8.3 和 1.9.0 使用 attr() 會有所差別呢?
想知道他們的差別,最好的方法還是看他們的原始碼:
1.8.3 attr():
attr: function( elem, name, value, pass ) { 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 ) { return; } if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { return jQuery( elem )[ name ]( value ); } // Fallback to prop when attributes are not supported if ( typeof elem.getAttribute === "undefined" ) { return jQuery.prop( elem, name, value ); } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); // 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 ) { if ( value === null ) { jQuery.removeAttr( elem, name ); return; } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { elem.setAttribute( name, value + "" ); return value; } } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined return ret === null ? undefined : ret; } }
1.9.0 attr():
attr: function( elem, name, value, pass ) { 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 ) { return; } if ( pass && jQuery.isFunction( jQuery.fn[ name ] ) ) { return jQuery( elem )[ name ]( value ); } // Fallback to prop when attributes are not supported if ( typeof elem.getAttribute === "undefined" ) { return jQuery.prop( elem, name, value ); } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); // 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 ) { if ( value === null ) { jQuery.removeAttr( elem, name ); return; } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { elem.setAttribute( name, value + "" ); return value; } } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined return ret === null ? undefined : ret; } }
1.8.3 和1.9.0 的prop() 是一樣的:
prop: function( elem, name, value ) { var ret, hooks, notxml, nType = elem.nodeType; // don't get/set properties on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); if ( notxml ) { // Fix name and attach hooks 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 ]; } } }
首先,我们看下 attr() 和 prop() 的区别:
attr() 里面,最关键的两行代码
elem.setAttribute( name, value + "" ); ret = elem.getAttribute( name );
很明显的看出来,使用的 DOM 的 API setAttribute() 和 getAttribute() 方法操作的属性元素节点。
prop() 里面,最关键的两行代码
return ( elem[ name ] = value );return elem[ name ];
可以理解为 document.getElementById(el)[name] = value,这是转化成 element 的一个属性。
对比调试 1.9.0 和 1.8.3 的 attr() 方法,发现两者的区别在于
hooks.get( elem, name ))
返回的值不一样,具体的实现:
1.8.3 中
boolHook = { get: function( elem, name ) { // Align boolean attributes with corresponding properties // Fall back to attribute presence where some booleans are not supported var attrNode, property = jQuery.prop( elem, name ); return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? name.toLowerCase() : undefined; } }
1.9.0 中
boolHook = { get: function( elem, name ) { var // Use .prop to determine if this attribute is understood as boolean prop = jQuery.prop( elem, name ), // Fetch it accordingly attr = typeof prop === "boolean" && elem.getAttribute( name ), detail = typeof prop === "boolean" ? getSetInput && getSetAttribute ? attr != null : // oldIE fabricates an empty string for missing boolean attributes // and conflates checked/selected into attroperties ruseDefault.test( name ) ? elem[ jQuery.camelCase( "default-" + name ) ] : !!attr : // fetch an attribute node for properties not recognized as boolean elem.getAttributeNode( name ); return detail && detail.value !== false ? name.toLowerCase() : undefined; } }
由此可见,1.9.0 开始不建议使用 attr() 来对具有 true 和 false 两个属性的属性进行操作了。
那么我们的结论是:
具有 true 和 false 两个属性的属性,如 checked, selected 或者 disabled 使用prop(),其他的使用 attr(),具体见下表:
以上是jquery中什麼時候使用attr(),什麼時候使用prop()?的詳細內容。更多資訊請關注PHP中文網其他相關文章!