var nodeHook, boolHook,rclass = /[\t\r\n\f]/g,rreturn = /\r/g,rfocusable = /^(?:input|select|textarea|button)$/i;jQuery.fn.extend({attr: function( name, value ) { //遍历this //arguments.length > 1,jQuery.attr(this[i],name,value),返回this //arguments.length <= 1,jQuery.attr(this[i],name,value),返回thisreturn jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );},removeAttr: function( name ) {return this.each(function() {jQuery.removeAttr( this, name );});},prop: function( name, value ) {return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );},removeProp: function( name ) {return this.each(function() {delete this[ jQuery.propFix[ name ] || name ];});},//$('.div1').addClass('box2 box3');addClass: function( value ) {var classes, elem, cur, clazz, j,i = 0,len = this.length,proceed = typeof value === "string" && value;//是字符串返回字符串,不是返回flase/*$('div').addClass( function(index){alert(index);return 'box'+index;});*/if ( jQuery.isFunction( value ) ) {console.log(this);//这里的this是jQuery对象,Object { 0: <div#div1.box>, 1: <div#div2.box>, 2: <div#div3.box>, length: 3},通过return ( context || rootjQuery ).find('.div1')原生方法获得,里面每一个是节点对象不是jQuery对象return this.each(function( j ) {console.log(this);//这里不是jQuery对象是dom节点对象,<div id='div1'></div>,<div id='div2'></div>,<div id='div3'></div>console.log(jQuery( this ));//jQuery( this )是jQuery对象,Object { 0: <div#div1.box>, context: <div#div1.box>, length: 1 },Object { 0: <div#div2.box>, context: <div#div2.box>, length: 1 },Object { 0: <div#div3.box>, context: <div#div3.box>, length: 1 }/*jQuery( this )走的是if ( selector.nodeType ) {//节点都有nodeType属性this.context = this[0] = selector;this.length = 1;return this;*/jQuery( this ).addClass( value.call( this, j, this.className ) );});}if ( proceed ) {// 把字符串正则分割成数组classes = ( value || "" ).match( core_rnotwhite ) || [];for ( ; i < len; i++ ) {elem = this[ i ];//不是元素节点返回false,elem.className元素有没有class属性,有就合并(重复不合并),cur是之前的classcur = elem.nodeType === 1 && ( elem.className ?//非空格转换成空格( " " + elem.className + " " ).replace( rclass, " " ) :" ");if ( cur ) {j = 0;while ( (clazz = classes[j++]) ) {if ( cur.indexOf( " " + clazz + " " ) < 0 ) {cur += clazz + " ";}}//前后去空格elem.className = jQuery.trim( cur );}}}return this;},removeClass: function( value ) {var classes, elem, cur, clazz, j,i = 0,len = this.length,//先执行&&再||,proceed为true参数长度是0删除所有或者参数是字符串,为false传的不是字符串proceed = arguments.length === 0 || typeof value === "string" && value;if ( jQuery.isFunction( value ) ) {return this.each(function( j ) {jQuery( this ).removeClass( value.call( this, j, this.className ) );});}if ( proceed ) {classes = ( value || "" ).match( core_rnotwhite ) || [];for ( ; i < len; i++ ) {elem = this[ i ];// This expression is here for better compressibility (see addClass)cur = elem.nodeType === 1 && ( elem.className ?( " " + elem.className + " " ).replace( rclass, " " ) :"");if ( cur ) {j = 0;while ( (clazz = classes[j++]) ) {// Remove *all* instanceswhile ( cur.indexOf( " " + clazz + " " ) >= 0 ) {cur = cur.replace( " " + clazz + " ", " " );}}elem.className = value ? jQuery.trim( cur ) : "";}}}return this;},toggleClass: function( value, stateVal ) {var type = typeof value;//$('#div1').toggleClass('box2 box3',true);//有没有都是add//$('#div1').toggleClass('box2 box3',false);//有没有都是删除if ( typeof stateVal === "boolean" && type === "string" ) {//真就添加,假就删除return stateVal ? this.addClass( value ) : this.removeClass( value );}if ( jQuery.isFunction( value ) ) {return this.each(function( i ) {jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );});}//$('#div1').toggleClass('box2 box3')return this.each(function() {if ( type === "string" ) {// toggle individual class namesvar className,i = 0,self = jQuery( this ),//转成jQuery对象,hasClass是jQuery对象的方法。//空格分割成数组classNames = value.match( core_rnotwhite ) || [];while ( (className = classNames[ i++ ]) ) {// check each className given, space separated listif ( self.hasClass( className ) ) {self.removeClass( className );} else {self.addClass( className );}}// Toggle whole class name//$('#div1').toggleClass(false);} else if ( type === core_strundefined || type === "boolean" ) {if ( this.className ) {// store className if setdata_priv.set( this, "__className__", this.className );}// If the element has a class name or if we're passed "false",// then remove the whole classname (if there was one, the above saved it).// Otherwise bring back whatever was previously saved (if anything),// falling back to the empty string if nothing was stored.this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";}});},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;},val: function( value ) {var hooks, ret, isFunction,elem = this[0];//$('#input1').val()if ( !arguments.length ) {//获取if ( elem ) {//只获取第一个元素//hooks兼容处理,jQuery.valHooks[ elem.type ]在valHooks 这个json中找不到就找jQuery.valHooks[ elem.nodeName.toLowerCase() ]hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; /* valHooks: { hooks = option: { //elem.type || elem.nodeName.toLowerCase()get: function( elem ) {}}, hooks = select: {get: function( elem ) {},set: function( elem, value ) {}}下面的: hooks = radio: { set: function( elem ) {}get: function( elem, value ) {}}, hooks = checkbox: {set: function( elem ) {},get: function( elem, value ) {}} } */if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {return ret;}//不再hooks里面ret = elem.value;return typeof ret === "string" ?// handle most common string casesret.replace(rreturn, "") :// handle cases where value is null/undef or numberret == null ? "" : ret;}return;}//设置isFunction = jQuery.isFunction( value );return this.each(function( i ) {var val;if ( this.nodeType !== 1 ) {return;}if ( isFunction ) {val = value.call( this, i, jQuery( this ).val() );} else {val = value;}// Treat null/undefined as ""; convert numbers to stringif ( val == null ) {//$('#input1').val(null);val = "";} else if ( typeof val === "number" ) {//$('#input1').val(123123);val += "";//转成字符串} else if ( jQuery.isArray( val ) ) {//$('#input2').val(['hello']);val = jQuery.map(val, function ( value ) {return value == null ? "" : value + "";});}hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];// If set returns undefined, fall back to normal settingif ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {this.value = val;}});} });jQuery.extend({//静态属性只能通过jQuery静态方式调valHooks: {//option-get,select-get.select-set 兼容性处理 option: {get: function( elem ) {// attributes.value is undefined in Blackberry 4.7 but// uses .value. See #6932var val = elem.attributes.value;//val不存在输出elem.value,val存在specified为false走elem.textreturn !val || val.specified ? elem.value : elem.text;}},select: {//$('select').val()get: function( elem ) {var value, option,options = elem.options,//下拉选项index = elem.selectedIndex,//当前索引值//select只选了一个或者没有选,one为true,就是单选one = elem.type === "select-one" || index < 0,//one为true时单选values是空,one是false时多选values是一个数组存储所有的选择的多个values = one ? null : [],//单选时max是当前索引加1,多选时是下拉选项的长度max = one ? index + 1 : options.length,// i = index < 0 ?max /*index < 0没有选择时one=true,i=max=0*/ :one ? index/*index >= 0有选择时,select-one单选one=true,i=index,max=index+1,*/ :0 /*index >= 0有选择时,不是select-one多选one=false,i=0,max=options.length*/;// 没有选择不进入循环,不获取select的val()//有选择单选,i=index,只获取index的val()//有选择好多选,全部获取for ( ; i < max; i++ ) {option = options[ i ];//js对象// IE6-9 doesn't update selected after form reset (#2551)if ( ( option.selected || i === index ) &&// Don't return options that are disabled or in a disabled optgroup( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {// Get the specific value for the optionvalue = jQuery( option ).val();//转成jQuery对象// We don't need an array for one selectsif ( one ) {return value;}// Multi-Selects return an array values.push( value );}}return values;},// $('#select').val(111);//111被选中了set: function( elem, value ) {var optionSet, option,options = elem.options,//所有的下拉选项,js对象values = jQuery.makeArray( value ),//转成数组i = options.length;while ( i-- ) {//遍历option = options[ i ];if ( (option.selected = jQuery.inArray( jQuery(option).val(), values ) >= 0) ) {//在数组里面就把她设为选中optionSet = true;}}// force browsers to behave consistently when non-matching value is setif ( !optionSet ) {//都没有elem.selectedIndex = -1;}return values;}}},attr: function( elem, name, value ) {var hooks, ret,nType = elem.nodeType;// 节点不存在,或者文本、属性、注释节点if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {return;}// core_strundefined = typeof undefined,if ( typeof elem.getAttribute === core_strundefined ) {//$(document).attr('title','hello'); 走这里通过.设置return jQuery.prop( elem, name, value );}// 1是元素节点,if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {name = name.toLowerCase();//只有type才做兼容性处理hooks = jQuery.attrHooks[ name ] ||//$('input').attr('checked',true);//没问题,做兼容了( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );}if ( value !== undefined ) {//设置 //$('#div1').attr('miaov',null); 调用removeif ( value === null ) {jQuery.removeAttr( elem, name ); //hooks中,set方法存在,就调用set方法并且返回值存在,就返回返回值} else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {return ret;//有兼容性执行兼容操作,返回值 } else {//没有兼容性操作设置值elem.setAttribute( name, value + "" );return value;} //hooks中,get方法存在,就调用get方法并且返回值存在,就返回返回值} else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {//获取,有兼容性返回值return ret;} else {//获取没有兼容性时ret = jQuery.find.attr( elem, name );// Non-existent attributes return null, we normalize to undefinedreturn ret == null ?undefined :ret;}},removeAttr: function( elem, value ) {var name, propName,i = 0,//$('#div1').removeAttr('maio href id');attrNames = value && value.match( core_rnotwhite );//core_rnotwhite = /\S+/g, 非空格,返回数组if ( attrNames && elem.nodeType === 1 ) {while ( (name = attrNames[i++]) ) {/*propFix: {"for": "htmlFor","class": "className"},*/// $('#div1').removeAttr('class');propName = jQuery.propFix[ name ] || name;// Boolean attributes get special treatment (#10870)if ( jQuery.expr.match.bool.test( name ) ) {// $('#div1').removeAttr('checked');elem[ propName ] = false;}elem.removeAttribute( name );//调用原生 }}}, //hooks = jQuery.attrHooks[ name ] attrHooks: {type: {//只有name = 'type',才会有有兼容性判断。set: function( elem, value ) {//只有set说明兼容只是针对设置没有获取if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {//单选值的兼容// Setting the type on a radio button after the value resets the value in IE6-9// Reset value to default in case type is set after value during creation//当设置type = 'radio'时IE会有兼容性问题,所以要先设置类型才设置值var val = elem.value;elem.setAttribute( "type", value );if ( val ) {elem.value = val;}return value;}}}},propFix: {"for": "htmlFor","class": "className"},prop: function( elem, name, value ) {var ret, hooks, notxml,nType = elem.nodeType;// don't get/set properties on text, comment and attribute nodesif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {return;}notxml = nType !== 1 || !jQuery.isXMLDoc( elem );if ( notxml ) {// Fix name and attach hooksname = jQuery.propFix[ name ] || name;hooks = jQuery.propHooks[ name ];//兼容性处理 }if ( value !== undefined ) {//设置值return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?ret :( elem[ name ] = value );//prop使用的是.操作 } else {//获取值return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?ret :elem[ name ];}},propHooks: {tabIndex: {//光标切换顺序,只对tabIndex属性做兼容get: function( elem ) {//只对get方法做兼容return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?elem.tabIndex :-1;}}} });// Hooks for boolean attributes boolHook = {set: function( elem, value, name ) {if ( value === false ) {// Remove boolean attributes when set to false jQuery.removeAttr( elem, name );} else {elem.setAttribute( name, name );}return name;} }; jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {var getter = jQuery.expr.attrHandle[ name ] || jQuery.find.attr;jQuery.expr.attrHandle[ name ] = function( elem, name, isXML ) {var fn = jQuery.expr.attrHandle[ name ],ret = isXML ?undefined :/* jshint eqeqeq: false */// Temporarily disable this handler to check existence(jQuery.expr.attrHandle[ name ] = undefined) !=getter( elem, name, isXML ) ?name.toLowerCase() :null;// Restore handlerjQuery.expr.attrHandle[ name ] = fn;return ret;}; });// Support: IE9+ // Selectedness for an option in an optgroup can be inaccurate if ( !jQuery.support.optSelected ) {jQuery.propHooks.selected = {get: function( elem ) {var parent = elem.parentNode;if ( parent && parent.parentNode ) {parent.parentNode.selectedIndex;}return null;}}; }jQuery.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable" ], function() {//value = callback.call( obj[ i ], i, obj[ i ] );jQuery.propFix[ this.toLowerCase() ] = this; });/* valHooks: { hooks = radio: { set: function( elem ) {}get: function( elem, value ) {}}, hooks = checkbox: {set: function( elem ) {},get: function( elem, value ) {}} } */ jQuery.each([ "radio", "checkbox" ], function() {jQuery.valHooks[ this ] = {//$('#radio').val(['hello']);set: function( elem, value ) {if ( jQuery.isArray( value ) ) {return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );//设置选中状态 }}};if ( !jQuery.support.checkOn ) {//有的话做处理,没有不做处理 //获取单选框和复选框的value值时绝大多数浏览器返回的都是on,有些是空的,jQuery.valHooks[ this ].get = function( elem ) {// Support: Webkit// "" is returned instead of "on" if a value isn't specifiedreturn elem.getAttribute("value") === null ? "on" : elem.value;};} });