jQuery val()方法及valHooks源码解读
val: function( value ) { var hooks, ret, isFunction, elem = this[0]; if ( !arguments.length ) {//无参数 if ( elem ) {//第一个元素 //考虑元素是checkbox,radio,option或者select的情况,这时有val钩子 hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; //如果钩子存在且有get 且获取的值不为undefined,返回该值 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { return ret; } //否则,ret就是元素的value ret = elem.value; //如果值是字符串 return typeof ret === "string" ? //将换行符替换为"" ret.replace(rreturn, "") : // 如果值不是字符串,考虑null和undefined的情况,如果是null或undefined,ret置为"" ret == null ? "" : ret; } return; } //判断传入的参数value是否是函数 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; } //如果val是null或者undefined,设为"" if ( val == null ) { val = ""; //如果val是数字,转为字符串 } else if ( typeof val === "number" ) { val += ""; //如果val是数组 } else if ( jQuery.isArray( val ) ) {//处理数组中的undefined null 和数字 val = jQuery.map( val, function( value ) { return value == null ? "" : value + ""; }); } //同样地,考虑元素是checkbox,radio,option或者select的情况 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; // 如果set返回了undefined,回退到正常值val if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } }); }
valHooks:
jQuery.extend({ valHooks: { option: { get: function( elem ) { //调用Sizzle.attr方法 var val = jQuery.find.attr( elem, "value" ); //如果val为null或undefined,取elem的text值 return val != null ? val : // Support: IE10-11+ // option.text throws exceptions (#14686, #14858) jQuery.trim( jQuery.text( elem ) ); } }, select: { get: function( elem ) { var value, option, options = elem.options, index = elem.selectedIndex,//当前选中项 单选默认0,多选默认-1 //如果是单选下拉框或者当前没有选中项,one为true one = elem.type === "select-one" || index < 0, values = one ? null : [],//one为true,则values为null,否则为[] max = one ? index + 1 : options.length,//单选最大为1,多选为options.length i = index < 0 ? max : one ? index : 0; // Loop through all the selected options for ( ; i < max; i++ ) {//遍历 option = options[ i ]; // 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 // 如果support.optDisabled为true,值为option.disabled取反 // 如果为假,值为option的属性disabled的值 // 如果值为null ( support.optDisabled ? !option.disabled : option.getAttribute( "disabled" ) === null ) && //且 如果select的disabled为假或者 optgroup的disabled为真 ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { // Get the specific value for the option value = jQuery( option ).val(); // We don't need an array for one selects if ( one ) {//单选直接返回 return value; } // Multi-Selects return an array values.push( value );//多选推入数组 } } return values;//多选且没有没有默认项,不经过循环直接返回 }, set: function( elem, value ) { var optionSet, option, options = elem.options, values = jQuery.makeArray( value ),//转为数组,value可以是任何值 "a"=>["a"] i = options.length;//选项数量 //遍历 while ( i-- ) { option = options[ i ]; //如果当前选项的值在values数组中,selected为true,否则为false //可以用于设置多选的下拉单值 /*用法: <select name="" id="" class="slt" multiple> <option value="a">aaa</option> <option value="b">bbbb</option> <option value="c">ccccc</option> </select> <script> $('.slt').val(["a","c"]); </script> */ if ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) { optionSet = true;//标识 } } // force browsers to behave consistently when non-matching value is set if ( !optionSet ) { elem.selectedIndex = -1; } return values; } } } }); // Radios and checkboxes getter/setter jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = { set: function( elem, value ) { if ( jQuery.isArray( value ) ) { //如果传入的value是数组,判断当前元素的值是否在value数组中 //存在,则设置checked为true,并返回true,不存在则checked为false,并返回false /* 用法: <input type="checkbox" class="ck" value="a"> <input type="checkbox" class="ck" value="b"> <script> $('.ck').val(["a","b"]); </script> */ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); } } }; if ( !support.checkOn ) { jQuery.valHooks[ this ].get = function( elem ) { //如果未指定value,返回on //如果是 <input type="checkbox" class="ck" value>或者 //<input type="checkbox" class="ck" value="">这两种,返回的是"" return elem.getAttribute("value") === null ? "on" : elem.value; }; } });
可以看到,jQ的valHooks共有四个成员:
1、option
2、select
3、checkbox
4、radio
option中只有get方法,因为它的目的是在option中没有value值的时候去取中间的text值。
checkbox和radio中,set方法是考虑到同时为多个复选或者单选框设置值的情况,而get方法是考虑了没有初始化value时返回默认值“on”
select的set方法同复选单选框类似,而get方法中,如果是单选,直接返回value,如果是多选且有选中项,遍历后将结果推入数组最后返回数组,此外,它处理了option的disabled为true的情况,如果为true,获取不到值。这一点也是我的疑问,它为什么要这样做→ →
<select name="" id="slt" class="slt"> <option value="a">aaa</option> <option value="b">bbbb</option> <option value="c" selected disabled>ccccc</option> </select> <script> console.log($('#slt').val(),document.getElementById("slt").value); </script>
// null "c"
hi,我的新博客地址:ysha.me !!