jQuery源码分析-09属性操作
来源:互联网 发布:淘宝店铺三钻多少分 编辑:程序博客网 时间:2024/06/10 20:50
属性操作主要介绍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源码分析-09属性操作
- jQuery源码分析(版本1.6.1)___属性操作
- jQuery-1.9.1源码分析系列(八) 属性操作
- jQuery源码分析——对元素属性的操作
- .JQuery文档分析2--JQuery核心与属性操作
- JQuery文档分析2--JQuery核心与属性操作
- [ jQuery ] jQuery 源码分析!
- jQuery源码分析-12 DOM操作-Manipulation-核心函数.domManip()
- jQuery-1.9.1源码分析系列(九) CSS操作
- jQuery-1.9.1源码分析系列(十一) DOM操作
- jQuery-1.9.1源码分析系列(十二) 筛选操作
- jQuery源码分析---仿栈与队列的操作
- jquery操作属性
- jquery属性操作
- jQuery 属性操作
- jQuery操作元素属性
- jQuery操作元素属性
- jQuery 属性操作
- 取带runas的一些优秀小工具介绍
- 算法之排序小结1---插入排序(Java)
- ssh整合过程检验文件中校验属性的编写
- C#关闭显示器,打开显示器
- ActionBar取消底部分隔线效果
- jQuery源码分析-09属性操作
- C语言之快速排序
- Solr文档 (官方资料)
- printf的时候打印%号
- asp.net 六大对象之Request、Response
- 还原sql2008数据库提示数据库正在使用
- scrollView中放满button,无法滑动
- new MySqlParameter("@val", 0).Value == null的异常
- UML类图关系