博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jQuery1.9.1--attr,prop与val方法源码分析
阅读量:4614 次
发布时间:2019-06-09

本文共 21272 字,大约阅读时间需要 70 分钟。

这里只介绍这几个方法的源码,这部分引用了一个技巧,钩子对象,用来做兼容fixed的对象,后面也有一些使用。钩子对象具体的兼容细节这里就不详解了。

1 var nodeHook, boolHook,  2         rclass = /[\t\r\n]/g,  3         rreturn = /\r/g,  4         rfocusable = /^(?:input|select|textarea|button|object)$/i,  5         rclickable = /^(?:a|area)$/i,  6         rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,  7         ruseDefault = /^(?:checked|selected)$/i,  8         getSetAttribute = jQuery.support.getSetAttribute,  9         getSetInput = jQuery.support.input; 10  11     jQuery.fn.extend({ 12         attr: function (name, value) { 13             return jQuery.access(this, jQuery.attr, name, value, arguments.length > 1); 14         }, 15         removeAttr: function (name) { 16             return this.each(function () { 17                 jQuery.removeAttr(this, name); 18             }); 19         }, 20         prop: function (name, value) { 21             return jQuery.access(this, jQuery.prop, name, value, arguments.length > 1); 22         }, 23         removeProp: function (name) { 24             name = jQuery.propFix[ name ] || name; 25             return this.each(function () { 26                 // try/catch handles cases where IE balks (such as removing a property on window) 27                 try { 28                     this[ name ] = undefined; 29                     delete this[ name ]; 30                 } catch (e) { 31                 } 32             }); 33         }, 34         addClass: function (value) { 35             var classes, elem, cur, clazz, j, 36                 i = 0, 37                 len = this.length, 38                 proceed = typeof value === "string" && value; 39  40             if (jQuery.isFunction(value)) { 41                 return this.each(function (j) { 42                     jQuery(this).addClass(value.call(this, j, this.className)); 43                 }); 44             } 45  46             if (proceed) { 47                 // The disjunction here is for better compressibility (see removeClass) 48                 classes = ( value || "" ).match(core_rnotwhite) || []; 49  50                 for (; i < len; i++) { 51                     elem = this[ i ]; 52                     cur = elem.nodeType === 1 && ( elem.className ? 53                         ( " " + elem.className + " " ).replace(rclass, " ") : 54                         " " 55                         ); 56  57                     if (cur) { 58                         j = 0; 59                         while ((clazz = classes[j++])) { 60                             if (cur.indexOf(" " + clazz + " ") < 0) { 61                                 cur += clazz + " "; 62                             } 63                         } 64                         elem.className = jQuery.trim(cur); 65  66                     } 67                 } 68             } 69  70             return this; 71         }, 72         removeClass: function (value) { 73             var classes, elem, cur, clazz, j, 74                 i = 0, 75                 len = this.length, 76                 proceed = arguments.length === 0 || typeof value === "string" && value; 77  78             if (jQuery.isFunction(value)) { 79                 return this.each(function (j) { 80                     jQuery(this).removeClass(value.call(this, j, this.className)); 81                 }); 82             } 83             if (proceed) { 84                 classes = ( value || "" ).match(core_rnotwhite) || []; 85  86                 for (; i < len; i++) { 87                     elem = this[ i ]; 88                     // This expression is here for better compressibility (see addClass) 89                     cur = elem.nodeType === 1 && ( elem.className ? 90                         ( " " + elem.className + " " ).replace(rclass, " ") : 91                         "" 92                         ); 93  94                     if (cur) { 95                         j = 0; 96                         while ((clazz = classes[j++])) { 97                             // Remove *all* instances 98                             while (cur.indexOf(" " + clazz + " ") >= 0) { 99                                 cur = cur.replace(" " + clazz + " ", " ");100                             }101                         }102                         elem.className = value ? jQuery.trim(cur) : "";103                     }104                 }105             }106 107             return this;108         },109         toggleClass: function (value, stateVal) {110             var type = typeof value,111                 isBool = typeof stateVal === "boolean";112 113             if (jQuery.isFunction(value)) {114                 return this.each(function (i) {115                     jQuery(this).toggleClass(value.call(this, i, this.className, stateVal), stateVal);116                 });117             }118 119             return this.each(function () {120                 if (type === "string") {121                     // toggle individual class names122                     var className,123                         i = 0,124                         self = jQuery(this),125                         state = stateVal,126                         classNames = value.match(core_rnotwhite) || [];127 128                     while ((className = classNames[ i++ ])) {129                         // check each className given, space separated list130                         state = isBool ? state : !self.hasClass(className);131                         self[ state ? "addClass" : "removeClass" ](className);132                     }133 134                     // Toggle whole class name135                 } else if (type === core_strundefined || type === "boolean") {136                     if (this.className) {137                         // store className if set138                         jQuery._data(this, "__className__", this.className);139                     }140 141                     // If the element has a class name or if we're passed "false",142                     // then remove the whole classname (if there was one, the above saved it).143                     // Otherwise bring back whatever was previously saved (if anything),144                     // falling back to the empty string if nothing was stored.145                     this.className = this.className || value === false ? "" : jQuery._data(this, "__className__") || "";146                 }147             });148         },149         hasClass: function (selector) {150             var className = " " + selector + " ",151                 i = 0,152                 l = this.length;153             for (; i < l; i++) {154                 if (this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf(className) >= 0) {155                     return true;156                 }157             }158 159             return false;160         },161         val: function (value) {162             var ret, hooks, isFunction,163             // 获取伪数组中的第一个元素164                 elem = this[0];165 166             // 如果没有传参,说明是获取value值167             if (!arguments.length) {168                 if (elem) {169                     // 尝试获取valHooks钩子对象,170                     // 如果元素不具有type类型的钩子对象,171                     // 则尝试赋值元素标签键值的钩子对象172                     hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];173 174                     // 如果存在钩子对象且有get方法且get返回的不是undefined175                     // 则返回get方法的返回值176                     if (hooks && "get" in hooks && (ret = hooks.get(elem, "value")) !== undefined) {177                         return ret;178                     }179 180                     // 否则没有相应的钩子对象,直接获取元素的value值181                     ret = elem.value;182 183                     // 如果ret是字符串,返回过滤掉制表符的字符串,184                     // 否则ret为空就返回空字符串,185                     // 否则返回ret186                     return typeof ret === "string" ?187                         // handle most common string cases188                         ret.replace(rreturn, "") :189                         ret == null ? "" : ret;190                 }191 192                 return;193             }194 195             // 下面是有参数的情况,说明是设置value值196 197             // 先判断value是否为函数198             isFunction = jQuery.isFunction(value);199 200             // 遍历元素集201             return this.each(function (i) {202                 var val,203                     self = jQuery(this);204 205                 if (this.nodeType !== 1) {206                     return;207                 }208 209                 // 如果value是函数就执行,然后给ret赋值返回的值210                 if (isFunction) {211                     val = value.call(this, i, self.val());212                 } else {213                     val = value;214                 }215 216                 // 如果value为null或undefined,转化为字符串217                 // 如果是数字类型也转换为字符串218                 // 如果是数组类型,使用map方法返回一个返回值数组219                 if (val == null) {220                     val = "";221                 } else if (typeof val === "number") {222                     val += "";223                 } else if (jQuery.isArray(val)) {224                     val = jQuery.map(val, function (value) {225                         return value == null ? "" : value + "";226                     });227                 }228 229                 // 尝试获取钩子对象230                 hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];231 232                 // 如果没有钩子对象,或者钩子对象没有set方法,233                 // 又或者set方法返回的值是undefined,234                 // 就使用正常操作235                 if (!hooks || !("set" in hooks) || hooks.set(this, val, "value") === undefined) {236                     this.value = val;237                 }238             });239         }240     });241 242     jQuery.extend({243         valHooks: {244             option: {245                 /*246                  获取option的value值247                  */248                 get: function (elem) {249                     // Blackberry 4.7的attributes.value为undefined但可以使用.value获取250                     var val = elem.attributes.value;251                     return !val || val.specified ? elem.value : elem.text;252                 }253             },254             /* 获取select的value值,如果是多选则返回数组 */255             select: {256                 get: function (elem) {257                     var value, option,258                         options = elem.options,259                         index = elem.selectedIndex,260                         one = elem.type === 'select-one' || index < 0,261                         values = one ? null : [],262                         max = one ? index + 1 : options.length,263                         i = index < 0 ? max :264                             one ? index : 0;265 266                     // 遍历所有选中的项267                     for (; i < max; i++) {268                         option = options[i];269 270                         // 旧版本IE不会更新选中项当表单重置后271                         if ((option.selected || i === index) &&272                             // 不返回被禁用的选项或者在被禁用的optgroup中273                             (jQuery.support.optDisabled ? !option.disabled : option.getAttribute('disabled') === null) &&274                             (!option.parentNode.disabled || !jQuery.nodeName(option.parentNode, 'optgroup'))275                             ) {276                             // 为option设置指定值277                             value = jQuery(option).val();278 279                             // 单选的话我们就不需要用数组了280                             if (one) {281                                 return value;282                             }283 284                             // 多选就返回数组285                             values.push(value);286                         }287                     }288 289                     return values;290                 },291                 set: function (elem, value) {292                     var values = jQuery.makeArray(value);293 294                     jQuery(elem).find('option').each(function () {295                         this.selected = jQuery.inArray(jQuery(this).val(), values) >= 0;296                     });297 298                     if (!values.length) {299                         elem.selectedIndex = -1;300                     }301                     return values;302                 }303             }304         },305         attr: function (elem, name, value) {306             var hooks, notxml, ret,307                 nType = elem.nodeType;308 309             // 如果elem的类型是文本,注释或者属性直接退出310             if (!elem || nType === 3 || nType === 8 || nType === 2) {311                 return;312             }313 314             // 当不支持attributes时,回退用prop方法315             if (typeof elem.getAttribute === core_strundefined) {316                 return jQuery.prop(elem, name, value);317             }318 319             // 是否非XML文档320             notxml = nType !== 1 || !jQuery.isXMLDoc(elem);321 322             // 如果钩子被定义了则抓取323             if (notxml) {324                 name = name.toLowerCase();325                 // 如果不存在attrHooks钩子对象就尝试获取boolHook的钩子对象,326                 // 否则就用nodeHook这个钩子对象327                 hooks = jQuery.attrHooks[name] || (rboolean.test(name) ? boolHook : nodeHook);328             }329 330             if (value !== undefined) {331                 // value为null就删除attr属性332                 if (value === null) {333                     jQuery.removeAttr(elem, name);334                 } else if (hooks && notxml && 'set' in hooks && (ret = hooks.set(elem, value, name)) !== undefined) {335                     // 否则如果存在钩子方法,则返回set方法的返回值336                     return ret;337                 } else {338                     // 其他情况就直接用setAttribute设置value339                     elem.setAttribute(name, value + '');340                 }341             } else if (hooks && notxml && 'get' in hooks && (ret = hooks.get(elem, name)) !== null) {342                 // 如果value是undefined,且存在钩子方法,343                 // 返回get方法的返回值344                 return ret;345             } else {346                 // 其他情况(无钩子对象)就使用getAttribute获取value347                 // 在IE9+,Flash对象没有.getAttribute348                 if (typeof elem.getAttribute !== core_strundefined) {349                     ret = elem.getAttribute(name);350 351                     return ret == null ?352                         undefined :353                         ret;354                 }355             }356         },357         removeAttr: function (elem, value) {358             var name, propName,359                 i = 0,360                 // value值可以是空格连接的多个value,361                 // 这里通过正则匹配非空字符串,返回匹配的数组362                 attrNames = value && value.match(core_rnotwhite);363 364             // 如果attrNames存在且elem是元素节点365             if (attrNames && elem.nodeType === 1) {366                 // 遍历attrNames数组367                 while ((name = attrNames[i++])) {368                     // 如果没有propFix对象(将name转换为正确的字符串)就直接使用name作为属性值369                     propName = jQuery.propFix[name] || name;370 371                     // 布尔值的属性需要特殊处理372                     if (rboolean.test(name)) {373                         // 如果不支持获取和设置属性且有selected或checked属性,374                         // 则将defaultName和propName设置为false375                         if (!getSetAttribute && ruseDefault.test(name)) {376                             elem[jQuery.camelCase('default-' + name)] = elem[propName] = false;377                         } else {378                             // 其他情况直接把propName属性设置为false379                             elem[propName] = false;380                         }381                     } else {382                         // 非布尔值属性就调用jQuery.attr方法383                         jQuery.attr(elem, name, '');384                     }385 386                     // 删除元素上的该属性387                     elem.removeAttribute(getSetAttribute ? name : propName);388                 }389             }390         },391         attrHooks: {392             type: {393                 set: function (elem, value) {394                     if (!jQuery.support.radioValue && value === 'radio' && jQuery.nodeName(elem, 'input')) {395                         // Setting the type on a radio button after the value resets the value in IE6-9396                         // Reset value to default in case type is set after value during creation397                         var val = elem.value;398                         elem.setAttribute('type', value);399                         if (val) {400                             elem.value = val;401                         }402                         return value;403                     }404                 }405             }406         },407         propFix: {408             tabindex: 'tabIndex',409             readonly: 'readOnly',410             'for': 'htmlFor',411             'class': 'className',412             maxlength: 'maxLength',413             cellspacing: 'cellSpacing',414             cellpadding: 'cellPadding',415             rowspan: 'rowSpan',416             colspan: 'colSpan',417             usemap: 'useMap',418             frameborder: 'frameBorder',419             contenteditable: 'contentEditable'420         },421         prop: function (elem, name, value) {422             var ret, hooks, notxml,423                 nType = elem.nodeType;424 425             if (!elem || nType === 3 || nType === 8 || nType === 2) {426                 return;427             }428 429             notxml = nType !== 1 || !jQuery.isXMLDoc(elem);430 431             // 如果elem不是xml文档元素,获取被fixed的name和钩子对象432             if (notxml) {433                 name = jQuery.propFix[name] || name;434                 hooks = jQuery.propHooks[name];435             }436 437             // 如果value不是undefined,说明是设置prop438             if (value !== undefined) {439                 // 如果有钩子对象且存在set方法,440                 // 返回非undefined的方法返回值,441                 // 否则正常情况下直接用elem[name]设置prop442                 if (hooks && 'set' in hooks && (ret = hooks.set(elem, value, name)) !== undefined) {443                     return ret;444                 } else {445                     return (elem[name] = value);446                 }447 448                 // 如果value是undefined,说明是获取prop属性值449             } else {450                 // 有钩子对象用其get方法,没有就用原生的方法451                 if (hooks && 'get' in hooks && (ret = hooks.get(elem, name)) !== null) {452                     return ret;453                 } else {454                     return elem[name];455                 }456             }457         },458         propHooks: {459             tabIndex: {460                 get: function (elem) {461                     // 当elem的tabindex没有被明确设置时,不会总返回正确的值462                     var attributeNode = elem.getAttributeNode('tabindex');463 464                     return attributeNode && attributeNode.specified ?465                         parseInt(attributeNode.value, 10) :466                         rfocusable.test(elem.nodeName) || rclickable.test(elem.nodeName) && elem.href ?467                             0 :468                             undefined;469                 }470             }471         }472     });473 474     // Hook for boolean attributes475     boolHook = {476         get: function (elem, name) {477             var478             // Use .prop to determine if this attribute is understood as boolean479                 prop = jQuery.prop(elem, name),480 481             // Fetch it accordingly482                 attr = typeof prop === "boolean" && elem.getAttribute(name),483                 detail = typeof prop === "boolean" ?484 485                     getSetInput && getSetAttribute ?486                         attr != null :487                         // oldIE fabricates an empty string for missing boolean attributes488                         // and conflates checked/selected into attroperties489                         ruseDefault.test(name) ?490                             elem[ jQuery.camelCase("default-" + name) ] :491                             !!attr :492 493                     // fetch an attribute node for properties not recognized as boolean494                     elem.getAttributeNode(name);495 496             return detail && detail.value !== false ?497                 name.toLowerCase() :498                 undefined;499         },500         set: function (elem, value, name) {501             if (value === false) {502                 // Remove boolean attributes when set to false503                 jQuery.removeAttr(elem, name);504             } else if (getSetInput && getSetAttribute || !ruseDefault.test(name)) {505                 // IE<8 needs the *property* name506                 elem.setAttribute(!getSetAttribute && jQuery.propFix[ name ] || name, name);507 508                 // Use defaultChecked and defaultSelected for oldIE509             } else {510                 elem[ jQuery.camelCase("default-" + name) ] = elem[ name ] = true;511             }512 513             return name;514         }515     };
View Code

 

 

转载于:https://www.cnblogs.com/webFrontDev/p/3189845.html

你可能感兴趣的文章
vue+element-ui实现表格checkbox单选
查看>>
select * 和select 1 以及 select count(*) 和select count(1)的区别
查看>>
进度条04
查看>>
Elsevier期刊投稿状态
查看>>
Heartbeat+LVS构建高可用负载均衡集群
查看>>
多表查询
查看>>
那些年我们扔过的漂流瓶
查看>>
javascript:巧用eval函数组装表单输入项为json对象
查看>>
为什么我们叫雪狼队
查看>>
wpf button变成圆角
查看>>
测试开发学习进阶教程 视频&PDF
查看>>
C#基础-连接Access与SQL Server
查看>>
autofac
查看>>
MacOS 系统终端上传文件到 linux 服务器
查看>>
Excel导出POI
查看>>
兼容性
查看>>
自动执行sftp命令的脚本
查看>>
转 Merkle Tree(默克尔树)算法解析
查看>>
网络编程基础之socket编程
查看>>
各种浏览器的user-agent和
查看>>