DOM对象实例方法prop源码:
prop: function( name, value ) {
return access( this, jQuery.prop, name, value, arguments.length > 1 );
}
如果传入一个参数,那么这时候value是undefined,第五个参数是false,为了方便我们还是附上access源码:
如果是获取属性(value是false,chainable和bulk都是false):调用fn(elem[0],key)那么回调jQuery.prop方法,传入参数第一个DOM对象和key值,也就是只是获取第一个DOM对象的属性值!这和attr获取时候的结果是一样的!
如果是设置属性:传入access里面第三个和第四个参数都存在,同时第五个参数是true,这时候为每一个调用对象的DOM对象都调用jQuery.prop方法传入的参数是DOM元素,key和value。如prop("prop_a","codePlayer")
var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
var i = 0,
length = elems.length,
bulk = key == null;
// Sets many values
if ( jQuery.type( key ) === "object" ) {
chainable = true;
for ( i in key ) {
jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
}
// Sets one value
} else if ( value !== undefined ) {
chainable = true;
if ( !jQuery.isFunction( value ) ) {
raw = true;
}
if ( bulk ) {
// 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 ) {
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;
};
jQuery.prop方法源码:
你要弄明白如果不通过下标形式对DOM赋值获得property属性,那么document.getElementById("n2").data_key就是false,但是这都
算是attribute!但是property和attribute也有交叉的地方,如id,calss和className等(可以通过firebug看出)。
jQuery.extend({
propFix: {
"for": "htmlFor",
"class": "className"
},
//prop里面调用prop(elem[0],"name")
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;
}
//不是XML元素
notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
if ( notxml ) {
// Fix name and attach hooks
//获取hooks,如果这个hooks已经存在,也就是内置的几种如selected,href,src等那么调用内部的set方法或者get方法
//如jQuery.propHooks["select"]就是内置的对象
name = jQuery.propFix[ name ] || name;
hooks = jQuery.propHooks[ name ];
}
//如果value不为空表示设置
if ( value !== undefined ) {
//设置成功返回set方法的返回值,否则返回elem的相应属性.但是必须注意:这里的propHooks里面的属性是固定的
return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
ret :( elem[ name ] = value );
} else {
//获取相应属性
return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
ret :
elem[ name ];
}
},
propFix:对tabindex等进行的处理
jQuery.each([
"tabIndex",
"readOnly",
"maxLength",
"cellSpacing",
"cellPadding",
"rowSpan",
"colSpan",
"useMap",
"frameBorder",
"contentEditable"
], function() {
jQuery.propFix[ this.toLowerCase() ] = this;
});
IE6/7下面enctype是encoding
// IE6/7 call enctype encoding
if ( !support.enctype ) {
jQuery.propFix.enctype = "encoding";
}
for修改为htmlFor,class是className,所以对于prop方法来说可以传入for也可以传入htmlFor等
propFix: {
"for": "htmlFor",
"class": "className"
}
tabIndex来说jQuery做了特殊的处理,也就是说我们获取tabIndex的时候是调用该hooks中的get!
var rfocusable = /^(?:input|select|textarea|button|object)$/i,
rclickable = /^(?:a|area)$/i;
propHooks: {
tabIndex: {
get: function( elem ) {
// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
// Use proper attribute retrieval(#12072)
var tabindex = jQuery.find.attr( elem, "tabindex" );//因为tabIndex如果没有设置可能会返回不正确的值!
//这里还是调用jQueyr.find.attr方法,不过传入的不是驼峰写法!如果调用该方法没有获取到有效的tabIndex
//那么要对标签进行判断,如果是input/select/textarea/button/object那么返回0;如果是a/area同时有href
//也返回0,否则返回-1!
return tabindex ?
parseInt( tabindex, 10 ) :
rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
0 :
-1;
}
}//End of tabIndex
}
});
对hrefNormalize进行分析:该方法判断是否能够获取到有效的href值!如果是返回true!
div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
a = div.getElementsByTagName("a")[ 0 ];
support.hrefNormalized = a.getAttribute("href") === "/a";
如果不能获取到有效的href属性值,那么我们用getAttribute("href")或者getAttribute("src")等,至于为什么加入第二个参数是为了在IE6/7下获取完整的src/href属性!
//如果获取hooks是undefined,那么直接返回elem[key]的值!
//我们看看jQuery中对propHooks进行设置的代码:
//代码一之href和src:
if ( !support.hrefNormalized ) {
// href/src property should get the full normalized URL (#10299/#12915)
jQuery.each([ "href", "src" ], function( i, name ) {
jQuery.propHooks[ name ] = {
get: function( elem ) {
return elem.getAttribute( name, 4 );
}
};
});
optSelected属性测试:
// Make sure that a selected-by-default option has a working selected property.
// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
select = document.createElement("select");
opt = select.appendChild( document.createElement("option") );
support.optSelected = opt.selected;
检测当一个option添加到select上时候该option是否被选中,也就是他的selected是否是true,如果是true表示被选中,如果是false表示没有被选中!如果没有被选中的时候我们要做兼容!也就是默认第一项被选中!
// Support: Safari, IE9+
// mis-reports the default selected property of an option
// Accessing the parent's selectedIndex property fixes it
//IE9+和Safari会错误的得到option的默认的selected属性,通过获取他父元素的selectedIndex解决这个bug
if ( !support.optSelected ) {
jQuery.propHooks.selected = {
get: function( elem ) {
var parent = elem.parentNode;
if ( parent ) {
parent.selectedIndex;
// Make sure that it also works with optgroups, see #5701
if ( parent.parentNode ) {
parent.parentNode.selectedIndex;
}
}
return null;//返回null,所以在prop方法里最后返回的还是elem["selected"]
}
};
}
jQuery中暂时没有找到其它的地方对jQuery.propHooks进行赋值。设置值的时候这个hook不存在,那么就会
调用elem[key]=value进行赋值!但是在attr方法中调用的是setAttribute方法!
总结:
(1)如果使用prop()
函数操作表单元素的checked
、selected
、disabled
等属性,如果该元素被选中(或禁用),则返回true
,否则(意即HTML中没有该属性)返回false
。之所以是这样还是因为底层用的是property访问的方法,不是用getAttribute方法!不选中的时候property返回false,attribute返回null!
(2)prop()
函数还可以设置或返回DOM元素的Element
对象上的某些属性,例如:tagName、selectedIndex、nodeName、nodeType、ownerDocument、defaultChecked和defaultSelected等属性。之所以能够获取是因为每一个元素在firebug下都能看到这个property!是property不是attributes,而且这些属性是不能被改变的,也就是说如果你把tagName设置为新的值,那么再次获取还是原来的值!
(3)在IE9及更早版本中,如果使用prop()
函数设置的属性值不是一个简单的原始值(String、Number、Boolean),并且在对应的DOM元素被销毁之前,该属性没有被移除,则可能会导致内存泄漏问题。如果你只是为了存储数据,建议你使用data()函数,以避免内存泄漏问题。
(4)但是从1.6开始,使用attr()
获取这些属性的返回值为String类型,如果被选中(或禁用)就返回checked
、selected
或disabled
,否则(即元素节点没有该属性)返回undefined
。并且,在某些版本中,这些属性值表示文档加载时的初始状态值,即使之后更改了这些元素的选中(或禁用)状态,对应的属性值也不会发生改变。1.11.1就是这样
(5)因为tabIndex如果没有设置可能会返回不正确的值!这里还是调用jQueyr.find.attr方法,不过传入的不是驼峰写法!如果调用该方法没有获取到有效的tabIndex那么要对标签进行判断,如果是input/select/textarea/button/object那么返回0;如果是a/area同时有href也返回0,否则返回-1!
(6)如果用prop方法访问for属性,可以用htmlFor也可以用for,因为prop方法有专门针对他的propFix,如果用attr访问for属性那么就只能是attr("for"),对于class也是一样的!(记住:这时候prop方法要变成驼峰)
(7)针对IE6/7获取URL会被修改的情况下,IE调用getAttribute方法时候传入了第二个参数为4,那么就能和其它浏览器一样不会串改URL!