前文对属性的设置、读取、删除方法做了分解,本文继续对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; } }); };