jQuery源码分析:jQuery对象属性设置(attr、access、$.attr)源代码分析

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 );

    }

});

你可能感兴趣的:(JQuery对象)