研究jQuery源码的时候发现access这个方法使用范围很大,而且代码比较绕,在这里做一个总结
一、简介
access()是一个多功能方法,作为set和get值来使用,在jQuery中有以下方法对它进行了调用:attr(),prop(),text(),html(),css(),data(),scrollLeft(),scrollTop()
二、函数调用
我们在使用以上函数的时候,通常的使用方法有以下几种:
1.获取属性值/文本值
$('xx').css('color');
$('xx').data('aaa');
$('xx').text();
$(document).scrollLeft();
$("input[type='checkbox']").prop("checked");
2.设置属性/文本值
$("input[type='checkbox']").prop("checked", true);
$("xx").css("color","red");
$("xx").css({ "color": "red", "background": "blue" });
//还有一种特殊方式
<div class="aa" style="color:red;">123</div>
$('.aa').text(function(index,text){
return Number(text)+1;
});//div的值被修改为124
三、参数和调用
我们先来看看access的参数
/**
elems : 一个元素的集合
fn : 回调函数
key : 对应.css("color","red"); 中的color
value : 对应.css("color","red"); 中的value
chainable : get/set的标识,用来判断返回不同的内容
emptyGet : 暂时发现只会被当成undefined来做判断调用
raw : 用来判断value是否为函数
**/
access: function( elems, fn, key, value, chainable, emptyGet, raw )
在css()中的调用方式:
css: function( name, value ) {
return jQuery.access( this, function( elem, name, value ) {
var styles, len,
map = {},
i = 0;
if ( jQuery.isArray( name ) ) {
styles = getStyles( elem );
len = name.length;
for ( ; i < len; i++ ) {
map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
}
return map;
}
return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
}, name, value, arguments.length > 1 );
}
在text()中的调用方式(注意key值):
text: function( value ) {
return jQuery.access( this, function( value ) {
return value === undefined ?
jQuery.text( this ) :
this.empty().append( ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) );
}, null, value, arguments.length );
}
在这里为了方便判断jQuery在text()、html()这种以文本操作和css()、prop()、data()等这种以属性操作的函数中做了一个区分:text()和html()的key参数被设置为null
接下来看看具体的代码
四、access方法具体解析
access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
var i = 0, //设置了一个循环起点
length = elems.length, //获取元素的长度对多个元素进行操作
bulk = key == null; //在这里判断是否为文本操作方法(text、html)会做不同的处理
// Sets many values
//如果参数以{key:value,key:value}的形式传进来会对这个对象进行遍历,然后递归引用access方法进行设置
if ( jQuery.type( key ) === "object" ) {
chainable = true; //标识操作为set
for ( i in key ) {
jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
}
// Sets one value
//此处判断文本操作(text(),html())设置字符串或者传入的是函数做处理
} else if ( value !== undefined ) {
chainable = true; //标识操作为set
if ( !jQuery.isFunction( value ) ) {
raw = true;
}
if ( bulk ) {
// Bulk operations run against the entire set
//如果value为文本在这里直接使用回调函数进行处理后下文不再做处理
if ( raw ) {
fn.call( elems, value );
fn = null;
// ...except when executing function values
//如果value为函数会在这里针对性的包装后在下边的if进行处理
} else {
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
};
}
}
//使用各函数的回调作为统一处理
if ( fn ) {
for ( ; i < length; i++ ) {
fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
}
}
}
//如果使用的是set功能则返回elems本身,否则为get功能此时:假如使用的是text(),html()方法则直接返回文本值,否则的话返回第一个元素的参数值。其他情况直接返回undefined(比如元素未找到)
return chainable ?
elems :
// Gets
bulk ?
fn.call( elems ) :
length ? fn( elems[0], key ) : emptyGet;
}
总结:函数走了两个方向,第一个方向是set:如果key存在并且为object时做了一个递归设置值的操作,如果key为null但是value有值的时候则是设置文本的操作(text(),html())此时做了一个细分,如果value为文本则直接使用上级的回调函数做处理(设置文本内容到html页面),如果value为函数,则使用函数处理后继续调用上级回调函数再次处理。
之后使用上级回调函数(包装回调函数)进行统一的处理
第二个方向get就是最后的return,此时如果走的是set返回了elems本身,如果走的是get则文本方法返回文本值,属性方法返回元素集合第一个属性的值,其他返回undefined