zoukankan      html  css  js  c++  java
  • jquery源码解析:addClass,toggleClass,hasClass详解

    这一课,我们将继续讲解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 = /[ f]/g, 是制表符, 是回车, 换行符,f是换页。这些都是空白符,不是空格,我们需要把空白符替换成空格,以防元素的class属性值之间用空白符隔开,而不是空格隔开的。比如:<div class="box1  box2">,这里的box1和box2之间的 就会替换成" "。

            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,因此放到下一课讲解。

    加油!

  • 相关阅读:
    eclipse中的Invalid text string (xxx).
    在jsp文件中出现Unknown tag (c:out)
    eclipse 界面复原
    ecilpse 纠错插件
    Multiple annotations found at this line:- The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path
    Port 8080 required by Tomcat v9.0 Server at localhost is already in use. The server may already be running in another process, or a system process may be using the port.
    调用第三方https接口
    调用第三方http接口
    创建带值枚举
    spring整合redis之Redis配置文件
  • 原文地址:https://www.cnblogs.com/chaojidan/p/4192529.html
Copyright © 2011-2022 走看看