jQuery源码分析:jQuery对象属性设置(attr、access、$.attr)源代码分析
2012-11-02 16:04 VVG 阅读(2442) 评论(1) 编辑 收藏 举报jQuery中设置对象属性有以下几种:
1、获取属性attr(name)
$("img").attr("src");
2、设置属性attr(name,value)
$("img").attr("src","test.jpg");
3、批量设置属性attr(properties)
$("img").attr({ src: "test.jpg", alt: "Test Image" });
4、为所有匹配的元素设置一个计算的属性值,由这个函数计算的值作为属性值。 attr(key, function(index, attr))
$("img").attr("title", function() { return this.src }); // 获取当前元素的src值作为title属性值
5、移除属性 removeAttr(name)
$("img").removeAttr("src");
其中都会用到jQuery对象的attr方法,attr的源代码如下:
jQuery.fn.extend({ attr: function( name, value ) { return access( this, name, value, true, jQuery.attr ); })
可以看到,attr只是起到一个传值的作用,然后返回的是access的返回值,再来看看access函数中的代码:
function access( elems, key, value, exec, fn, pass) { var length = elems.length; // 如果key是对象,则拆分成名值单独赋值 if ( typeof key === "object" ) { for ( var k in key ) { access( elems, k, key[k], exec, fn, value ); } return elems; } // 如果value含值,则给属性赋值 if ( value !== undefined ) { // 如果value为函数的时候综合判断是否需要执行此函数 // 判断VALUE是否为函数,是函数则exec为true exec = !pass && exec && jQuery.isFunction(value); // 拆分对象,单独赋值 for ( var i = 0; i < length; i++ ) { // 对单独的对象调用jQuery.attr,设置属性 // 如果value是函数则执行value.call( elems[i], i, fn( elems[i], key ) ) fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass); } // 返回对象数组 return elems; } // 如果上面的条件都不符合,length有值则获取属性值,无对象则为undefined return length ? fn( elems[0], key ) : undefined; }
access就像它单词的意思一样是一个入口,判断key、value值的不同类型,最终会把值传递给jQuery的静态方法attr处理,即($.attr()):
attr静态方法中分别对浏览器的兼容性、各种特殊属性做了相应的处理
jQuery.extend({ attrFn: { val: true, css: true, html: true, text: true, data: true, width: true, height: true, offset: true }, attr: function( elem, name, value, pass ) { // don't set attributes on text and comment nodes // 如果对象为空、文字、注释则返回undefined if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { return undefined; } // 如果 name为 val、css、html、text、data、width、height、offset // 则直接调用jquery对应的方法如:$('p').html(value); if ( pass && name in jQuery.attrFn ) { return jQuery(elem)[name](value); } // 不是xml文档 var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), // Whether we are setting (or getting) // 是否需要设置或者获取 set = value !== undefined; // Try to normalize/fix the name // 转换为适配的属性,如 class -> className name = notxml && jQuery.props[ name ] || name; // Only do all the following if this is a node (faster for style) // 元素element 对象 if ( elem.nodeType === 1 ) { // These attributes require special treatment // rspecialurl = /href|src|style/ var special = rspecialurl.test( name ); // Safari mis-reports the default selected property of an option // Accessing the parent's selectedIndex property fixes it /* * 以下为opselected的bug修复 * http://www.cnblogs.com/GrayZhang/archive/2010/10/28/feature-detection-jquery1-4.html * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <select id="optSelected"> </select> <script type="text/javascript"> var select = document.getElementById('optSelected'); var option = document.createElement('option'); select.appendChild(option); console.log(option.selected); </script> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 以下为各浏览器中运行结果: 浏览器 | 结果 ----------- | ----- IE6 | false IE7 | false IE8 | false IE9 beta | false Firefox 3.6 | true Chrome 7 | true Safari 5 | false 经测试,IE系列和Safari使用`appendChild`对空的`<select>`元素添加一个`<option>`后,该`<option>`的`selected`属性不会被默认设置为**true**。 该问题引起的BUG描述如下: > 部分浏览器在获取option的selected属性时,会错误地返回false。 该问题的解决方案是在访问`selected`属性时,先访问其父级`<select>`元素的`selectedIndex`属性,强迫浏览器计算`<option>`的`selected`属性, 以得到正确的值。需要注意的是`<option>`元素的父元素不一定是`<select>`,也有可能是`<optgroup>`。具体代码如下: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if (!support.optSelected) { var parent = option.parentNode; parent.selectedIndex; //处理optgroup时的情况 if (parent.parentNode) { parent.parentNode.selectedIndex; } } return option.selected; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ if ( name === "selected" && !jQuery.support.optSelected ) { var parent = elem.parentNode; if ( parent ) { parent.selectedIndex; // Make sure that it also works with optgroups, see #5701 if ( parent.parentNode ) { parent.parentNode.selectedIndex; } } } // If applicable, access the attribute via the DOM 0 way if ( name in elem && notxml && !special ) { if ( set ) { // We can't allow the type property to be changed (since it causes problems in IE) // rtype = /(button|input)/i, // button 与 input 不允许修改 type属性 if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { jQuery.error( "type property can't be changed" ); } elem[ name ] = value; } // browsers index elements by id/name on forms, give priority to attributes. // 元素为form if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { return elem.getAttributeNode( name ).nodeValue; } // 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/ if ( name === "tabIndex" ) { var attributeNode = elem.getAttributeNode( "tabIndex" ); return attributeNode && attributeNode.specified ? attributeNode.value : rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 0 : undefined; } return elem[ name ]; } if ( !jQuery.support.style && notxml && name === "style" ) { if ( set ) { elem.style.cssText = "" + value; } return elem.style.cssText; } if ( set ) { // convert the value to a string (all browsers do this but IE) see #1070 elem.setAttribute( name, "" + value ); } var attr = !jQuery.support.hrefNormalized && notxml && special ? // Some attributes require a special call on IE elem.getAttribute( name, 2 ) : elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined return attr === null ? undefined : attr; } // elem is actually elem.style ... set the style // Using attr for specific style information is now deprecated. Use style instead. return jQuery.style( elem, name, value ); } });
转载请注明出处:http://www.cnblogs.com/NNUF/