jquery源码解析:jQuery对元素属性的操作2

这一课,我们将继续讲解jQuery对元素属性操作的方法。

首先,我们先看一下这几个方法是如何使用的:

$("#div1").addClass("box1 box2");     //给元素div的class属性添加box1和box2

$("#div1").removeClass("box1");     //删除元素div的class属性值box1

$("#div1").toggleClass("box1");     //如果元素div的class属性值中有box1,那么就删除box1。如果没有,那么就添加box1.

$("#div1").hasClass("box1");   //元素div的class属性值是否有box1,如果有,就返回true,如果没有,就返回false。

然后,我们来看一下源码解析:

jQuery.fn.extend({

  ......

  addClass: function( value ) {
    var classes, elem, cur, clazz, j,
      i = 0,
        len = this.length,     //this指的是$("div")
          proceed = typeof value === "string" && value; //判断传入的参数是否是字符串。我们在例子中,传入的都是字符串的形式,其实此方法,还可以传入回调方法,比如:$("div").addClass(function(index){  return "box"+index; })  ,回调方法的返回值,将会作为addClass的参数传入。这段代码就会在第一个div的class属性中添加box0,在第二个div的class属性中添加box1,以此类推。

    if ( jQuery.isFunction( value ) ) {   //传入的参数是否是函数
      return this.each(function( j ) {
        jQuery( this ).addClass( value.call( this, j, this.className ) );  //回调方法的第一个参数是当前元素的index值,第二个参数是当前元素的class属性值。
      });
    }

    if ( proceed ) {   //如果是字符串
      classes = ( value || "" ).match( core_rnotwhite ) || [];  // core_rnotwhite = /\S+/g,把"box1 box2"转换成[box1,box2]

      for ( ; i < len; i++ ) {  //循环元素
        elem = this[ i ];
        cur = elem.nodeType === 1 && ( elem.className ? ( " " + elem.className + " " ).replace( rclass, " " ) :" ");   //如果是元素节点,就继续进行判断元素的class属性值是否存在,rclass = /[\t\r\n\f]/g,\t是制表符,\r是回车,\n换行符,\f是换页。这些都是空白符,不是空格,我们需要把空白符替换成空格,以防元素的class属性值之间用空白符隔开,而不是空格隔开的。比如:<div class="box1  box2">,这里的box1和box2之间的\t就会替换成" "。

        if ( cur ) {   // " ",为真,""为假。
          j = 0;
          while ( (clazz = classes[j++]) ) {
            if ( cur.indexOf( " " + clazz + " " ) < 0 ) {   //判断元素之前是否有此class属性值,没有才添加
              cur += clazz + " ";
            }
          }
          elem.className = jQuery.trim( cur );  //最后,去掉前后空格。

        }
      }
    }

    return this;
  },

  removeClass: function( value ) {
    var classes, elem, cur, clazz, j,
      i = 0,
        len = this.length,
          proceed = arguments.length === 0 || typeof value === "string" && value;  //&&优先级高于||,所以先执行后面的&&操作。当不传入什么参数时,将会删除此元素class所有的属性值。比如:$("#div1").removeClass(),div1元素的class属性值将会变成""。

    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 ];
        cur = elem.nodeType === 1 && ( elem.className ?( " " + elem.className + " " ).replace( rclass, " " ) :"");

        if ( cur ) {   //如果此元素有class属性值,就进入if语句。
          j = 0;
          while ( (clazz = classes[j++]) ) {
            while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { //如果存在,就把此值删除
              cur = cur.replace( " " + clazz + " ", " " );
            }
          }
          elem.className = value ? jQuery.trim( cur ) : "";  //如果没传入参数,就把元素的class属性值赋为""。
        }
      }
    }

    return this;   //链式操作
  },

  toggleClass: function( value, stateVal ) {   //第二个参数,如果为true,就代表addClass,如果为false,就代表removeClass。
    var type = typeof value;

    if ( typeof stateVal === "boolean" && type === "string" ) {  //$("div").toggleClass("box1 box2",true);
      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 );
      });
    }

    return this.each(function() {
      if ( type === "string" ) {
        var className,
          i = 0,
            self = jQuery( this ),
              classNames = value.match( core_rnotwhite ) || [];

        while ( (className = classNames[ i++ ]) ) {
          if ( self.hasClass( className ) ) {   //元素如果有此class属性值,就删除
            self.removeClass( className );
          } else {
            self.addClass( className );
          }
        }

      } else if ( type === core_strundefined || type === "boolean" ) {  //core_strundefined = undefined,如果是这种操作,$("#div1").toggleClass(false);或者$("#div1").toggleClass();就会进入else if语句。
        if ( this.className ) {   //如果此元素有class属性值,就把属性值存入jQuery缓存系统中。
          data_priv.set( this, "__className__", this.className );
        }

        this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";       //假设div1有class="box1 box2",那么执行$("#div1").toggleClass(false);或者$("#div1").toggleClass();将会把div1的class=""。之后,你再调用$("#div1").toggleClass(true);或者$("#div1").toggleClass();又会把dv1的class="box1 box2"。
      }
    });
  },

  hasClass: function( selector ) {
    var className = " " + selector + " ",
      i = 0,
        l = this.length;  
    for ( ; i < l; i++ ) {    //对所有匹配元素进行class的操作,也就是说$("div"),hasClass("box"),只要页面上的任何一个div的class属性值有box,就会返回true。
      if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
        return true;
      }
    }

    return false;
  },

  ......

});

下一课,将讲解最后一个对属性操作的方法val,因为此方法牵涉到valHooks,因此放到下一课讲解。

加油!

时间: 2024-10-08 23:34:41

jquery源码解析:jQuery对元素属性的操作2的相关文章

JQuery源码解析-JQuery的工具方法(5)

下面对最后这几个方法进行讲解. guid():唯一表示(内部) proxy():改变this指向 access(): 多功能值操作 now():当前时间 swap():css交换(内部) guid: 这个属性是对事件进行控制的,例如每次对dom元素进行绑定事件的时候,会通过这个属性进行绑定,这个属性每次自增,产生一个唯一的标示,所以对dom元素进行事件解绑等操作的时候,通过这个属性就可以找到. 源码: // A global GUID counter for objects guid: 1, p

JQuery源码解析-JQuery的工具方法(3)

这篇文章主要对下面这几个方法进行解释 error();抛出异常 parseHTML():解析节点 parseJSON():解析JSON parseXML:解析XML noop():空函数 globalEval():全局解析JS camelCase():转驼峰 nodeName():是否为指定节点(内部) error:方法: error方法的作用是抛出一个自定义异常,内部直接调用了原生解释的throw new Error error: function( msg ) { throw new Err

JQuery源码解析-JQuery的工具方法(2)

这篇对下面的方法进行讲解: isFunction():是否为函数 isArray():是否为数组 isWindow():是否为window isNumeric()是否为数字 type():判断数据类型 isPlainObject():是否为对象自变量 isEmptyObject():是否为空的对象 isFunction方法: 这个方法很简单,判断对象是否为函数,返回bool类型,看一下源码: // See test/unit/core.js for details concerning isFu

JQuery源码解析-JQuery的工具方法(4)

下面对这些方法进行讲解 each():遍历集合 trim():去前后空格 makeArray():类数组转换真数组 inArray():数组版indexOf merge():合并数组 grep():过滤新数组 map():映射新数组 each方法: each是遍历集合用的方法,也是一个加强版的循环操作.例如: var arr = { Name: 'jam', Age: 15 }; $.each(arr, function (key, val) { console.log(key + ":&quo

jQuery源码解析(jQuery对象的实例属性和方法)

1.记录版本号 以及 修正constructor指向 jquery: core_version, constructor: jQuery, 因为jQuery.prototype={ ... } 这种写法将自动生成的jQuery.prototype.constructor属性覆盖删除,所以需要重新修正(指向其构造函数 jQuery).2.init() 初始化方法: init()方法最终返回的是this -jQuery(其实是jQuery.prototype.init)方法的实例对象. 实例对象继承

五.jQuery源码解析之jQuery.extend(),jQuery.fn.extend()

给jQuery做过扩展或者制作过jQuery插件的人这两个方法东西可能不陌生.jQuery.extend([deep],target,object1,,object2...[objectN]) jQuery.fn.extend([deep],target,object1,,object2...[objectN])这两个属性都是用于合并两个或多个对象的属性到target对象.deep是布尔值,表示是否进行深度合并,默认是false,不执行深度合并.通过这种方式可以在jQuery或jQuery.fn

二.jQuery源码解析之构建jQuery之构建函数jQuery的7种用法

一:$(selectorStr[,限制范围]),接受一个选择器(符合jQuery规范的字符串),返回一个jQuery对象;二:$(htmlStr[,文档对象]),$(html[,json对象])传入html字符串,创建一个新的dom元素 三:$(dom元素),$(dom元素集合)将dom元素转换成jQuery对象.四:$(自定义对象)封装普通对象为jQuery对象.五:$(回调函数)绑定ready事件监听函数,当Dom加载完成时执行.六:$(jQuery对象)接受一个jQuery对象,返回一个j

jquery源码解析:代码结构分析

本系列是针对jquery2.0.3版本进行的讲解.此版本不支持IE8及以下版本. (function(){ (21, 94)     定义了一些变量和函数,   jQuery = function(){}; (96,283)   给jQuery对象添加一些属性和方法(实例方法,通过$("div")这类的jQuery实例对象来调用) (285,347)   extend : jQuery的继承方法 (349,817)   jQuery.extend():扩展一些工具方法(静态方法,直接通

十二.jQuery源码解析之.eq().first().last().slice()

eq(index):将集合中的索引为index的元素提取出来. first():返回集合中的第一个元素. .last():防护集合中的最后一个元素. .slice(start[,end]):返回集合中的给定区间段的元素. first()和last()调用eq(),eq()通过slice()实现,slice()通过 .pushStack()实现. 相关源码 285行:用法很奇特,通过一个"+"把可能为字符串的i转换成一个数值. 300~301:先借用数组方法slice()从当前jQuer

十一.jQuery源码解析之.pushStack()

pushStack()顾明思意,就是像桟中添加东西呗,现在看看他是如何添加东西的. 创建一个空的jQuery对象,然后把Dom元素集合放入这个jQuery对象中, 并保留对当前jQuery对象的引用. pushStack是核心方法之一,它为以下方法提供支持: jQuery对象遍历:.eq(),first(),.last(),.slice(),.map(); Dom查找,过滤:.find(),.not(),.filter(),.closest(),.add(),.andSelf(). Dom遍历: