前文 对属性的设置、读取、删除方法做了分解,本文继续对jQuery attributes模块分解。
jQuery.fn.addClass
/*
***********************************
* value: 字符串或者是函数,字符串可以通过空格分隔className
*/
jQuery.fn.addClass
=
function
( value ) {
var
classes, elem, cur, clazz, j,
i
= 0
,
len
=
this
.length,
proceed
=
typeof
value === "string" &&
value;
//
如果value是函数
if
( jQuery.isFunction( value ) ) {
//
则对所有元素迭代运行addClass
return
this
.each(
function
( j ) {
jQuery(
this
).addClass( value.call(
this
, j,
this
.className ) );
});
}
//
如果value是字符串
if
( proceed ) {
//
对value字符串分割成数组
classes = ( value || "" ).match( core_rnotwhite ) ||
[];
//
遍历元素
for
( ; i < len; i++
) {
elem
=
this
[ i ];
//
如果节点是元素,则获取原来的className
cur = elem.nodeType === 1 && ( elem.className ?
(
" " + elem.className + " " ).replace( rclass, " " ) :
//
替换掉换行符制表符等
" "
);
//
如果cur不为false,即节点是元素
if
( cur ) {
j
= 0
;
//
遍历classes组装成新的className应有的值
while
( (clazz = classes[j++
]) ) {
if
( cur.indexOf( " " + clazz + " " ) < 0
) {
cur
+= clazz + " "
;
}
}
//
对className赋值,去掉头尾空白
elem.className =
jQuery.trim( cur );
}
}
}
return
this
;
};
添加class的实现上还是比较简单的,利用elem.className来赋值。需要注意:
var rclass = /[\t\r\n]/g;
jQuery.fn.removeClass
jQuery.fn.removeClass =
function
( value ) {
var
classes, elem, cur, clazz, j,
i
= 0
,
len
=
this
.length,
//
参数是否正确
proceed = arguments.length === 0 ||
typeof
value === "string" &&
value;
//
如果value是函数
if
( jQuery.isFunction( value ) ) {
//
则对所有元素迭代运行removeClass
return
this
.each(
function
( j ) {
jQuery(
this
).removeClass( value.call(
this
, j,
this
.className ) );
});
}
//
如果参数正确
if
( proceed ) {
//
分隔value成为class字符串数组
classes = ( value || "" ).match( core_rnotwhite ) ||
[];
//
遍历
for
( ; i < len; i++
) {
elem
=
this
[ i ];
//
获取className并进行预处理
cur = elem.nodeType === 1 && ( elem.className ?
(
" " + elem.className + " " ).replace( rclass, " "
) :
""
);
//
如果是元素
if
( cur ) {
j
= 0
;
//
遍历所有class字符串
while
( (clazz = classes[j++
]) ) {
//
寻找是否有对应的字符串
while
( cur.indexOf( " " + clazz + " " ) >= 0
) {
//
有则去掉
cur = cur.replace( " " + clazz + " ", " "
);
}
}
//
给className赋值,并去掉头尾空格
elem.className = value ? jQuery.trim( cur ) : ""
;
}
}
}
return
this
;
};
删除class的实现和addClass非常像,只是通过indexOf和replace来替换掉需要删除的class。
jQuery.fn.toggleClass
jQuery.fn.toggleClass =
function
( value, stateVal ) {
var
type =
typeof
value,
isBool
=
typeof
stateVal === "boolean"
;
//
(⊙o⊙)…不说了,大家懂得
if
( jQuery.isFunction( value ) ) {
return
this
.each(
function
( i ) {
jQuery(
this
).toggleClass( value.call(
this
, i,
this
.className, stateVal), stateVal );
});
}
//
遍历所有元素
return
this
.each(
function
() {
//
如果value是字符串
if
( type === "string"
) {
var
className,
i
= 0
,
self
= jQuery(
this
),
state
=
stateVal,
//
将value转成classNames字符串数组
classNames = value.match( core_rnotwhite ) ||
[];
//
遍历
while
( (className = classNames[ i++
]) ) {
//
stateVal是布尔量,则直接设置为stateVal,否则判断元素是否不存在该className
state = isBool ? state : !
self.hasClass( className );
//
如果该className不存在则添加,否则删除
self[ state ? "addClass" : "removeClass"
]( className );
}
//
如果value的类型是undefined或者boolean
}
else
if
( type === "undefined" || type === "boolean"
) {
//
如果元素的className存在
if
(
this
.className ) {
//
将其存入缓存
jQuery._data(
this
, "__className__",
this
.className );
}
//
对className赋值,为空或者缓存中的值
this
.className =
this
.className || value ===
false
? "" : jQuery._data(
this
, "__className__" ) || ""
;
}
});
};
为了实现jQuery.fn.toggleClass还是花了很大功夫的。
缓存的利用使得toggleClass操作更加方便,而不需要记录以前是那些class。
jQuery.fn.hasClass
jQuery.fn.hasClass =
function
( selector ) {
var
className = " " + selector + " "
,
i
= 0
,
l
=
this
.length;
for
( ; i < l; i++
) {
if
(
this
[i].nodeType === 1 && (" " +
this
[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0
) {
return
true
;
}
}
return
false
;
};
这个函数通过indexOf来寻找className是否存在。
jQuery.fn.val
jQuery.fn.val =
function
( value ) {
var
hooks, ret, isFunction,
elem
=
this
[0
];
//
如果没有参数
if
( !
arguments.length ) {
//
如果元素存在
if
( elem ) {
//
得到相应的钩子
hooks = jQuery.valHooks[ elem.type ] ||
jQuery.valHooks[ elem.nodeName.toLowerCase() ];
//
通过钩子来得到值
if
( hooks && "get"
in
hooks && (ret = hooks.get( elem, "value" )) !==
undefined ) {
return
ret;
}
//
如果没得到钩子,则通过elem.value来返回值
ret =
elem.value;
//
如果ret是字符串
return
typeof
ret === "string" ?
//
将回车符替换
ret.replace(rreturn, ""
) :
//
如果ret是空的,则返回"",否则返回ret
ret ==
null
? ""
: ret;
}
return
;
}
//
value是否是函数
isFunction =
jQuery.isFunction( value );
//
遍历所有元素
return
this
.each(
function
( i ) {
var
val,
self
= jQuery(
this
);
if
(
this
.nodeType !== 1
) {
return
;
}
//
如果value是函数,则转成参数
if
( isFunction ) {
val
= value.call(
this
, i, self.val() );
}
else
{
val
=
value;
}
//
将null/undefined当成""
if
( val ==
null
) {
val
= ""
;
//
将数字转成字符串
}
else
if
(
typeof
val === "number"
) {
val
+= ""
;
//
如果是数组,则遍历数组
}
else
if
( jQuery.isArray( val ) ) {
val
= jQuery.map(val,
function
( value ) {
return
value ==
null
? "" : value + ""
;
});
}
//
获取相应钩子
hooks = jQuery.valHooks[
this
.type ] || jQuery.valHooks[
this
.nodeName.toLowerCase() ];
//
如果钩子无法设置,则使用通常的设置方法
if
( !hooks || !("set"
in
hooks) || hooks.set(
this
, val, "value" ) ===
undefined ) {
this
.value =
val;
}
});
};

