jQuery源码分析之prop和removeProp方法

来源:互联网 发布:淘宝代理协议书 编辑:程序博客网 时间:2024/06/02 06:31

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 valuesif ( 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 setif ( 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 :// Getsbulk ?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 nodesif ( !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 encodingif ( !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解决这个bugif ( !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 #5701if ( parent.parentNode ) {parent.parentNode.selectedIndex;}}return null;//返回null,所以在prop方法里最后返回的还是elem["selected"]}};}

jQuery中暂时没有找到其它的地方对jQuery.propHooks进行赋值。设置值的时候这个hook不存在,那么就会调用elem[key]=value进行赋值!但是在attr方法中调用的是setAttribute方法!
总结:

(1)如果使用prop()函数操作表单元素的checkedselecteddisabled等属性,如果该元素被选中(或禁用),则返回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类型,如果被选中(或禁用)就返回checkedselecteddisabled,否则(即元素节点没有该属性)返回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!

0 0