`

jQuery源码分析-09属性操作(转载)

 
阅读更多
属性操作主要介绍prop、attr、val三个接口的实现,相对于其他的接口,这三个的源码实现复杂,更容易让人混淆,一不小心就回使用错误的接口或返回错误的值,因此重点分析。

9.1 .prop() vs .attr()

9.1.1 概述

1.6.1相对1.5.x最大的改进,莫过于对属性.attr()的重写了。在1.6.1中,将.attr()一分为二: .attr()、.prop(),这是一个令人困惑的变更,也是一个破坏性的升级,会直接影响到无数的网站和项目升级到1.6。
简单的说,.attr()是通过setAttribute、getAttribute实现,.prop()则通过Element[ name ]实现:

jQuery.attr
setAttribute, getAttribute
jQuery.removeAttr
removeAttribute, removeAttributeNode(getAttributeNode )
jQuery.prop
Element[ name ]
jQuery.removeProp
delete Element[ name ]

事实上.attr()和.prop()的不同,是HTML属性(HTML attributes)和DOM属性(DOM properties)的不同。HTML属性解析的是HTML代码中的存在的属性,返回的总是字符串,而DOM属性解析的是DOM对象的属性,可能是字符串,也可能是一个对象,可能与HTML属性相同,也可能不同。


9.1.2 测试

看个例子,让我们对HTML属性和DOM属性的区别有个直观的概念:

HTML代码:

<a href="abc.html" class="csstest" style="font-size: 30px;">link</a>
<input type="text" value="123">
<input type="checkbox" checked="checked">

JavaScript代码:

console.info( $('#a').attr('href') ); // abc.html
console.info( $('#a').prop('href') ); // file:///H:/open/ws-nuysoft/com.jquery/jquery/abc.html

console.info( $('#a').attr('class') ); // csstest
console.info( $('#a').prop('class') ); // csstest

console.info( document.getElementById('a').getAttribute('class') ); // csstest
console.info( document.getElementById('a').className ); // csstest

console.info( $('#a').attr('style') ); // font-size: 30px;
console.info( $('#a').prop('style') ); // CSSStyleDeclaration { 0="font-size", fontSize="30px", ...}
console.info( document.getElementById('a').getAttribute('style') ); // font-size: 30px;
console.info( document.getElementById('a').style ); // CSSStyleDeclaration { 0="font-size", fontSize="30px", ...}

console.info( $('#text').attr('value') ); // 123
console.info( $('#text').prop('value') ); // 123

console.info( $('#checkbox').attr('checked') ); // checked
console.info( $('#checkbox').prop('checked') ); // true

可以看到HTML属性和DOM属性在属性名、属性值上都诸多不同。

9.1.3 区别

不同之处总结如下:
 属性名可能不同,尽管大部分的属性名还是相似或一致的
 HTML属性值总是返回字符串,DOM属性值则可能是整型、字符串、对象,可以获取更多的内容
 DOM属性总是返回当前的状态(值),而HTML属性(在大多数浏览)返回的初始化时的状态(值)
 DOM属性只能返回固定属性名的值,而HTML属性则可以返回在HTML代码中自定义的属性名的值
 相对于HTML属性的浏览器兼容问题,DOM属性名和属性值在浏览器之间的差异更小,并且DOM属性也有标准可依

9.1.4 建议

下边让我们回到.attr()和.prop(),经过以上测试和分析,可以得出对.attr()和.prop()的使用建议如下
 优先使用.prop(),因为.prop()总是返回最新的状态(值)
 只有涉及到自定义HTML属性时使用.attr(),或者可以说,忘掉.attr()吧


9.1.5 源码

 jQuery.attr

// 设置或获取HTML属性
// http://stackoverflow.com/questions/5874652/prop-vs-attr
attr: function( elem, name, value, pass ) {
    var nType = elem.nodeType;
  
    // don't get/set attributes on text, comment and attribute nodes
    // 忽略文本、注释、属性节点
    if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
       return undefined;
    }
    // 遇到与方法同名的属性,则执行方法
    // 如果遇到的是扩展或需要修正的属性,则执行相应的方法
    if ( pass && name in jQuery.attrFn ) {
       return jQuery( elem )[ name ]( value );
    }

    // Fallback to prop when attributes are not supported
    // 如果不支持getAttribute,则调用jQuery.prop
    // 求助于prop?prop是从attr中分化出来的,居然要求助于prop,看来attr要被放弃了
    if ( !("getAttribute" in elem) ) {
       return jQuery.prop( elem, name, value );
    }

    var ret, hooks,
       notxml = nType !== 1 || !jQuery.isXMLDoc( elem );

    // Normalize the name if needed
    // 格式化name(修正tabindex > tabIndex)
    name = notxml && jQuery.attrFix[ name ] || name;
    // 属性钩子:type tabIndex
    hooks = jQuery.attrHooks[ name ];

    // 如果没有name对应的钩子
    if ( !hooks ) {
       // Use boolHook for boolean attributes
       // 使用boolean钩子处理boolean属性
       if ( rboolean.test( name ) &&
           (typeof value === "boolean" || value === undefined || value.toLowerCase() === name.toLowerCase()) ) {
           // 使用 布尔钩子(静态方法对象):set get
           hooks = boolHook;

       // Use formHook for forms and if the name contains certain characters
       // 使用表单钩子
       } else if ( formHook && (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ) {
           // 使用 表单钩子(静态方法对象):set get
           hooks = formHook;
       }
    }
  
    // 如果value已定义,则设置或移除
    // 设置
    if ( value !== undefined ) {
       // typeof null === 'object' // true
       // typeof undefined === 'undefined' // true
       // null == undefined true
       // null === undefined false
       // value为null,则移除name属性
       // 注意这里用的都是恒等号
       if ( value === null ) {
           jQuery.removeAttr( elem, name );
           return undefined;

       }
       // 属性钩子、布尔钩子、表单钩子,如果有对应的钩子,则调用钩子的set方法
       else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
           return ret;

       } else {
           // 最后的最后,还是调用setAttribute,前边的各种钩子,都是修正属性
           // 强制将value转换为字符串
           elem.setAttribute( name, "" + value );
           return value;
       }
    // 如果value是undefined,说明是取属性值,如果对应的钩子的有get方法,则调用钩子的get方法
    } else if ( hooks && "get" in hooks && notxml ) {
       return hooks.get( elem, name );

    } else {
       // 最后的最后:getAttribute
       ret = elem.getAttribute( name );

       // Non-existent attributes return null, we normalize to undefined
       // 不存在的属性返回null,格式化为undefined
       return ret === null ?
           undefined :
           ret;
    }
}

 jQuery.prop

// 设置或获取DOM属性
prop: function( elem, name, value ) {
    var nType = elem.nodeType;

    // don't get/set properties on text, comment and attribute nodes
    // 忽略文本、注释、属性节点
    if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
       return undefined;
    }

    var ret, hooks,
       notxml = nType !== 1 || !jQuery.isXMLDoc( elem );

    // Try to normalize/fix the name
    // 属性名name修正
    name = notxml && jQuery.propFix[ name ] || name;
  
    hooks = jQuery.propHooks[ name ];
    // 设置
    // 看着prop的实现是不是很眼熟?嗯,和attr的思路类似!
    if ( value !== undefined ) {
       // 如果钩子存在set方法,则调用钩子的set方法
       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 )) !== undefined ) {
           return ret;

       } else {
           return elem[ name ];
       }
    }
}

 jQuery.fn.attr、jQuery.fn.prop
内部通过jQuery.access调用jQuery.attr、jQuery.prop实现

attr: function( name, value ) {
    return jQuery.access( this, name, value, true, jQuery.attr );
},

prop: function( name, value ) {
    return jQuery.access( this, name, value, true, jQuery.prop );
}

 jQuery.access

// Mutifunctional method to get and set values to a collection
// The value/s can be optionally by executed if its a function
// 多功能函数,读取或设置集合的属性值;值为函数时会被执行
// fn:jQuery.fn.css, jQuery.fn.attr, jQuery.fn.prop
access: function( elems, key, value, exec, fn, pass ) {
    var length = elems.length;

    // Setting many attributes
    // 如果有多个属性,则迭代
    if ( typeof key === "object" ) {
       for ( var k in key ) {
           jQuery.access( elems, k, key[k], exec, fn, value );
       }
       return elems;
    }

    // Setting one attribute
    // 只设置一个属性
    if ( value !== undefined ) {
       // Optionally, function values get executed if exec is true
       exec = !pass && exec && jQuery.isFunction(value);
       // 调用fn
       for ( var i = 0; i < length; i++ ) {
           fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
       }

       return elems;
    }

    // Getting an attribute
    // 读取属性
    return length ? fn( elems[0], key ) : undefined;
}
分享到:
评论

相关推荐

    jQuery源码分析-插件

    jQuery源码分析-插件

    jQuery源码分析-初步

    jQuery源码分析-初步

    jQuery源码分析-事件(1).

    jQuery源码分析-事件(1).

    jQuery源码分析-魔术方法

    jQuery源码分析-魔术方法

    jQuery源码分析-事件(2).

    jQuery源码分析-事件(2).

    jQuery源码分析-03构造jQuery对象

    ### jQuery源码分析—构造jQuery对象 #### 一、源码结构概览 根据所提供的文件内容,本节将深入分析如何构建jQuery对象及其核心构造逻辑。首先,让我们从整体上理解jQuery构造函数的设计思路。 ##### 总体结构 ...

    jquery插件jquery-ui-1.8.2.custom.min.js

    《jQuery UI与jQuery插件深度解析——以jquery-ui-1.8.2.custom.min.js为例》 在Web开发领域,jQuery库以其简洁易用的API和强大的功能深受开发者喜爱。而jQuery UI作为jQuery的一个扩展,提供了丰富的用户界面组件...

    jquery-ui-1.8.16.custom.min.js/jquery-ui-1.8.16.custom.css

    这个压缩包包含两个关键文件:`jquery-ui-1.8.16.custom.min.js` 和 `jquery-ui-1.8.16.custom.css`,这些都是jQuery UI的特定版本,即1.8.16。这个版本在当时是一个广泛使用的稳定版本,提供了丰富的功能和组件。 ...

    jquery.editable-select

    jQuery 是一个广泛使用的 JavaScript 库,简化了 DOM 操作、事件处理、动画以及Ajax交互。`jquery.editable-select` 就是建立在 jQuery 之上,因此在使用前需要确保页面中已经引入了 jQuery。 2. **选择器的增强**...

    jquery.datepicker-zh-CN.js

    &lt;script src="./public/js/jquery-ui-1.10.3.min.js"&gt; &lt;script src="./public/js/jquery.datepicker-zh-CN.js"&gt;&lt;/script&gt; &lt;link href="./public/css/jqueryui/jquery-ui-1.10.3.min.css" rel="stylesheet"&gt; $( "#...

    插件jquery-ui-timepicker-addon.js

    jquery插件jquery-ui-timepicker-addon.j

    jQuery源码 jQuery源码 jQuery源码

    jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码jQuery源码...

    jquery-ui-datepicker中文版

    jquery-ui-日期框扩展成时间框 jquery-ui时间框 基于别人的代码进行修改 jquery-ui-1.8.16.custom.css文件末尾加入以下代码 .ui-timepicker-div .ui-widget-header{ margin-bottom: 8px; } .ui-timepicker-div dl{ ...

    jquery-migrate-3.0.0.min.js 含源码

    jquery-migrate-3.0.0.min.js 含源码 包含以下文件: jquery-migrate-3.0.0.min.js jquery-migrate-3.0.0.js // 这个是源码哦 截至2017.11.21, jQuery3.x 最新最稳定版本

    jQuery-, jQuery源码解读 -- jQuery v1.10.2.zip

    源码分析可以让我们理解jQuery如何使用CSS属性和时间函数实现平滑的动画效果。 7. **插件扩展机制** jQuery的插件系统是其灵活性的关键。通过研究`$.fn.extend()`和`$.extend()`,我们可以学习如何编写自己的...

    Jquery源码分析 源码

    - **模块化**:jQuery源码采用模块化设计,如核心功能、选择器、遍历、属性操作、事件等都是独立模块,便于维护和扩展。 - **工厂函数**:$(selector)是jQuery的工厂函数,它接受字符串、DOM元素或jQuery对象,...

    139.jQuery源码分析-魔术方法.rar

    《jQuery源码分析——魔术方法》 jQuery,作为一款广泛使用的JavaScript库,以其简洁的API和强大的功能赢得了开发者们的喜爱。在深入理解jQuery的工作原理时,我们常常会遇到一些“魔术方法”,这些方法在特定场景...

Global site tag (gtag.js) - Google Analytics