jQuery attributes提供了文档节点的属性操作方法。
为了更好的理解,我们先解决jQuery core中的access参数设置函数。
jQuery.access
jQuery.access是一个专用于参数设置以及读取的方法。
在 jQuery链式操作 中我们对BigInteger的值获取是通过方法val来获取的,很显然此时val后面不能再链式操作了。所以:
如果要读取参数值,那么这个操作就不能链式操作。
/*
************************
* elems: 接受操作的元素组
* fn: 设置或读取函数
* key: 要设置的属性
* value: 要设置的值,也可以是函数
* chainable: 是否可以链式操作,即是读还是写操作
* emptyGet: 读取如果为空用什么表示
* raw: value能否直接传给fn,如果的确就是想将属性设置成函数value,那么要把这个值设成true
*/
jQuery.access
=
function
( elems, fn, key, value, chainable, emptyGet, raw ) {
var
i = 0
,
length
=
elems.length,
//
key是否为空
bulk = key ==
null
;
//
设置许多属性
if
( jQuery.type( key ) === "object"
) {
chainable
=
true
;
for
( i
in
key ) {
//
迭代执行设置一个值
jQuery.access( elems, fn, i, key[i],
true
, emptyGet, raw );
}
//
只设置一个值
}
else
if
( value !==
undefined ) {
chainable
=
true
;
//
如果value不是函数
if
( !
jQuery.isFunction( value ) ) {
raw
=
true
;
}
//
如果key为空
if
( bulk ) {
//
如果raw为true,即value不是函数
if
( raw ) {
//
执行fn,其this为elems,参数为value
fn.call( elems, value );
fn
=
null
;
//
如果value是函数
}
else
{
//
用bulk保存fn
bulk =
fn;
//
将fn变成特定形式
fn =
function
( elem, key, value ) {
return
bulk.call( jQuery( elem ), value );
};
}
}
//
如果fn存在
if
( fn ) {
//
遍历所有elems
for
( ; i < length; i++
) {
//
value是函数则运行fn(elem, key, value.call(elem, i, fn(elem, key)))
//
value非函数则运行fn(elem, key, value)
fn( elems[i], key, raw ?
value : value.call( elems[i], i, fn( elems[i], key ) ) );
}
}
}
//
如果是可链式操作的则返回elems
return
chainable ?
elems :
//
否则则是读取操作
bulk ?
fn.call( elems ) :
//
否则如果长度不为0,则返回fn( elems[0], key ),否则返回空
length ? fn( elems[0
], key ) : emptyGet;
}
jQuery官方文档没有该函数,应该说这是jQuery的一个内部工具。主要是为了实现jQuery中设置与读取复用性逻辑以及其内循环的,也就是为了节省写代码而已。
jQuery.fn.attr()
fn也就是jQuery实例对象的方法集。
fn中的方法attr也就是我们常用的attr方法。
如获取em标签的title属性:
var
title = $("em").attr("title");
那么这个函数式怎么实现的呢?
jQuery.fn.attr =
function
( name, value ) {
return
jQuery.access(
this
, jQuery.attr, name, value, arguments.length > 1
);
};
当参数长度为0或只为1时,则是读取操作,不能链式操作。
而这里用的设置函数是jQuery.attr,即实际运行时会运行jQuery.attr(elem, name, value)。
那么jQuery.attr是如何实现的呢?
/*
**************************
* elem: 要操作的元素
* name: 元素的属性名
* value: 要改变的值
*/
jQuery.attr
=
function
( elem, name, value ) {
var
ret, hooks, notxml,
nType
=
elem.nodeType;
//
不处理text,comment,attribute节点
if
( !elem || nType === 3 || nType === 8 || nType === 2
) {
return
;
}
//
如果属性不支持则使用jQuery.prop
if
(
typeof
elem.getAttribute === "undefined"
) {
return
jQuery.prop( elem, name, value );
}
//
是否不是XML
notxml = nType !== 1 || !
jQuery.isXMLDoc( elem );
//
如果不是XML
if
( notxml ) {
//
那么所有属性名应当是小写
name =
name.toLowerCase();
//
如果属性定义了,那么就抓住必要的钩子,解决IE6-9的相关问题
hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ?
boolHook : nodeHook );
}
//
如果value不是没有定义,即写入操作
if
( value !==
undefined ) {
//
如果value为空,则是删除操作
if
( value ===
null
) {
jQuery.removeAttr( elem, name );
//
如果钩子有set方法,则设置了之后,返回其值
}
else
if
( hooks && notxml && "set"
in
hooks && (ret = hooks.set( elem, value, name )) !==
undefined ) {
return
ret;
//
否则使用setAttribute方法
}
else
{
elem.setAttribute( name, value
+ ""
);
return
value;
}
//
如果是读取操作,如果钩子有get方法,则通过get得到返回值
}
else
if
( hooks && notxml && "get"
in
hooks && (ret = hooks.get( elem, name )) !==
null
) {
return
ret;
//
如果没有get方法
}
else
{
//
IE9+中Flash对象没有.getAttrubute方法,判断防止错误
if
(
typeof
elem.getAttribute !== "undefined"
) {
ret
=
elem.getAttribute( name );
}
//
返回undefined或则值
return
ret ==
null
?
undefined :
ret;
}
};
jQuery.removeAttr
removeAttr =
function
( elem, value ) {
var
name, propName,
i
= 0
,
//
分解value成为多个属性的数组
attrNames = value &&
value.match( core_rnotwhite );
//
如果有要删除的属性名
if
( attrNames && elem.nodeType === 1
) {
//
遍历所有属性名
while
( (name = attrNames[i++
]) ) {
//
看看需不需要用propFix来修改名字,不用直接用name
propName = jQuery.propFix[ name ] ||
name;
//
如果属性是布尔量先改成false
if
( rboolean.test( name ) ) {
elem[ propName ]
=
false
;
}
//
删除属性
elem.removeAttribute( name );
}
}
};
jQuery.propFix干了什么呢?
实际只是修改一下属性名,比如很多人喜欢用class来表示css类名,但实际上是className。
jQuery.propFix = {
tabindex:
"tabIndex"
,
readonly:
"readOnly"
,
"for": "htmlFor"
,
"class": "className"
,
maxlength:
"maxLength"
,
cellspacing:
"cellSpacing"
,
cellpadding:
"cellPadding"
,
rowspan:
"rowSpan"
,
colspan:
"colSpan"
,
usemap:
"useMap"
,
frameborder:
"frameBorder"
,
contenteditable:
"contentEditable"
};
jQuery.fn.removeAttr
这个函数实现比较简单,只是用each方法来调用jQuery.removeAttr而已。
jQuery.fn.removeAttr =
function
( name ) {
return
this
.each(
function
() {
jQuery.removeAttr(
this
, name );
});
};
jQuery.fn.prop
jQuery.fn.prop =
function
( name, value ) {
return
jQuery.access(
this
, jQuery.prop, name, value, arguments.length > 1
);
};
可见jQuery.fn.prop和jQuery.fn.attr差不多。
jQuery.prop
jQuery.prop =
function
( elem, name, value ) {
var
ret, hooks, notxml,
nType
=
elem.nodeType;
if
( !elem || nType === 3 || nType === 8 || nType === 2
) {
return
;
}
notxml
= nType !== 1 || !
jQuery.isXMLDoc( elem );
if
( notxml ) {
//
修复name和钩子
name = jQuery.propFix[ name ] ||
name;
hooks
=
jQuery.propHooks[ name ];
}
if
( value !==
undefined ) {
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 )) !==
null
) {
return
ret;
}
else
{
return
elem[ name ];
}
}
};
由于和jQuery.attr差不多,就不备注了。
jQuery.fn.removeProp
removeProp =
function
( name ) {
name
= jQuery.propFix[ name ] ||
name;
return
this
.each(
function
() {
//
try/catch handles cases where IE balks (such as removing a property on window)
try
{
this
[ name ] =
undefined;
delete
this
[ name ];
}
catch
( e ) {}
});
};
removeProp相对简单些,只是通过each将所有元素的属性设为undefined然后delete掉而已。
Attrubute和Property
从源代码我们可以发现,jQuery.attr如果找不到相应的方法会使用jQuery.prop。
jQuery 1.6加入jQuery.prop方法后,对很多人来说可能根本没啥用,因为用jQuery.attr方法肯定是对的。
但jQuery.attr和jQuery.prop到底差别在哪里呢?
这是Attrubute和Property的差别。
jQuery.attr方法会处理Attrubute和Property,但jQuery.prop只处理Property。
虽然这两个单词都可以翻译成“属性”,但是这两个实际上是不同的。
我们用一个例子来说明这个问题:
function
Demo(){
var
attrs =
{};
this
.name = "Bob"
;
this
.setAttr =
function
(name, value){
attrs[name]
=
value;
return
value;
}
this
.getAttr =
function
(name){
return
attrs[name];
}
}
那么对于一个实例:
var
i =
new
Demo();
i.name
//
Property
i.setAttr("name", "Tom"
);
i.getAttr(
"name")
//
Attrubute
所以jQuery文档中对jQuery.prop的解释是: 获取在匹配的元素集中的第一个元素的属性值。

