有了之前的几篇对于jQuery.attributes相关的研究,是时候分析jQuery.attr的源码了
jQuery.fn.extend({ attr: function (name, value) { }, removeAttr: function (name) { }, prop: function (name, value) { }, removeProp: function (name) { }, hasClass: function () {}, addClass:function () {}, toggleClass:function () {}, val: function () {}});jQuery.extend({ attr: function () { }, removeAttr: function () { }, prop: function () { },});
jQuery.fn.extend({ /** * 向被选元素添加一个或多个类 * @param value 'aclass' 'aclass bclass dclass',function () {} */ addClass: function (value) { var classes, elem, cur, clazz, j, i = 0, len = this.length, proceed = typeof value === "string" && value; //检测value是否为字符串 /** * $('#box').addClass(function (elem,oldClassName) { * return 'm-general-abc'; * }); * * 如果是个函数,那么逐个遍历现有元素,递归addClass方法 */ if (jQuery.isFunction(value)) { return this.each(function (j) { jQuery(this).addClass(value.call(this, j, this.className)); }); } // 如果是个字符串,那就执行正真的添加 if (proceed) { // The disjunction here is for better compressibility (see removeClass) classes = ( value || "" ).match(core_rnotwhite) || []; //将value用空格分开成一个数组 classes = value.split(//s+/); for (; i < len; i++) { //遍历所有的元素 elem = this[ i ]; cur = elem.nodeType === 1 && ( elem.className ? //检测是否为HTMLElement ( " " + elem.className + " " ).replace(rclass, " ") : //去掉换行什么的,两边加上空格,防止出错 " " //如果没有class的话,那就等于一个空格 ); if (cur) { j = 0; while ((clazz = classes[j++])) { //遍历所有的classes if (cur.indexOf(" " + clazz + " ") < 0) { //如果没有的话,才加入,如有,跳出了就 cur += clazz + " "; } } elem.className = jQuery.trim(cur); //设置className,并且trim一下 } } } // 链式结构,返回被封装的元素 return this; }, removeClass: function (value) { var classes, elem, cur, clazz, j, i = 0, len = this.length, 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* instances while (cur.indexOf(" " + clazz + " ") >= 0) { cur = cur.replace(" " + clazz + " ", " "); //如果存在,就删除 } } elem.className = value ? jQuery.trim(cur) : ""; //重新设置,如果没了,就设为空 } } } // 链式结构,返回被封装的元素 return this; }, /** * 设置或移除被选元素的一个或多个类进行切换 * 该方法检查每个元素中指定的类。如果不存在则添加类,如果已设置则删除之。这就是所谓的切换效果。 * @param value String:类名 Function:规定返回需要添加或删除的一个或多个类名的函数$(selector).toggleClass(function(index,class,switch),switch) * @param stateVal 规定是否添加(true)或移除(false)类 为true不存在,则添加.为false,已存在,则删除 * @returns {*} */ toggleClass: function (value, stateVal) { var type = typeof value, isBool = typeof stateVal === "boolean"; /** * $('#box').toggleClass(function (elem,oldClassName,stateVal) { * return 'm-general-abc'; * }); */ if (jQuery.isFunction(value)) { return this.each(function (i) { jQuery(this).toggleClass(value.call(this, i, this.className, stateVal), stateVal); }); } return this.each(function () { if (type === "string") { // toggle individual class names var className, i = 0, self = jQuery(this), state = stateVal, classNames = value.match(core_rnotwhite) || []; while ((className = classNames[ i++ ])) { //遍历所有的classNames // check each className given, space separated list //如果stateVal是布尔值,那么就去state,如果不是,就看hasClass是否有 //按照逻辑,执行添加或者删除class函数 state = isBool ? state : !self.hasClass(className); self[ state ? "addClass" : "removeClass" ](className); } // Toggle whole class name // 如果没有传入type或者type是个布尔值,那么就取当前DOM元素的className属性,用缓存系统将__className__设置成当前的className // } else if (type === core_strundefined || type === "boolean") { if (this.className) { // store className if set jQuery._data(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. // 这里就判断是否value为false,如果是,就将className设置为空,否则,将className从缓存系统里取出来,设置回去 this.className = this.className || value === false ? "" : jQuery._data(this, "__className__") || ""; } }); }, /** * 检查被选元素是否包含指定的 class * @param selector selector 类名 * @returns {boolean} 返回true表示包含,返回false,表示未包含 */ 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; }});
jQuery.fn.extend({ attr: function (name, value) { return 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) {
新闻热点
疑难解答