JQuery source code parsing addClass (), removeClass (), toggleClass () and hasClass ()

Time:2019-8-13

First,$().addClass()
Effect:
Add one or more class names to the target element

Source code:

// Add one or more class names to the target element
    // Source 8401 lines
    addClass: function( value ) {
      var classes, elem, cur, curValue, clazz, j, finalValue,
        i = 0;
      // If the value of addClass (value) is a function
      // Then call the target element this to call the function
      if ( isFunction( value ) ) {
        return this.each( function( j ) {
          // function(index,currentclass)
          // index corresponds to j, and its function is to obtain subscripts of multiple target elements.
          // CurrtClass corresponds to getClass (this). Its purpose is to get the class name of the current element and add spaces easily.
          jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
        } );
      }
      // Convert (multiple) class names to array form
      classes = classesToArray( value );
      if ( classes.length ) {
        // Multiple target elements
        while ( ( elem = this[ i++ ] ) ) {
          // Get the current value
          curValue = getClass( elem );
          // If the target element is an element node, wrap "+value+" around the space.
          cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );

          if ( cur ) {
            j = 0;
            // One class name after another
            while ( ( clazz = classes[ j++ ] ) ) {
              // If the current element does not repeat the class name to be added, add it
              if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
                cur += clazz + " ";
              }
            }
            // Finally, confirm whether the processed set of class names is the same as the pre-processed set of class names.
            // If the same, set Attribute, re-render, otherwise no re-rendering (performance optimization)
            // Only assign if different to avoid unneeded rendering.
            finalValue = stripAndCollapse( cur );
            if ( curValue !== finalValue ) {
              // Finally, add the class name through setAttribute
              elem.setAttribute( "class", finalValue );
            }
          }
        }
      }
      return this;
    },

Analysis:
(1)getClass()
Effect:
Get the class name of the target element

Source code:

// Source code 8377 lines
  function getClass( elem ) {
    return elem.getAttribute && elem.getAttribute( "class" ) || "";
  }

(2)classesToArray
Effect:
Convert (multiple) class names to array form

Source code:

// Source code 8382 lines
  function classesToArray( value ) {
    // The element's className, if it has more than one class name, is saved as an array, and is returned directly.
    if ( Array.isArray( value ) ) {
      return value;
    }
    // If the element class name is string type
    if ( typeof value === "string" ) {
      return value.match( rnothtmlwhite ) || [];
    }
    return [];
  }

(3)stripAndCollapse
Effect:
Separate vaues with spaces and then stitch them together with spaces

Source code:

// Source code 8370 lines
  // Strip and collapse whitespace according to HTML spec
  // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
  function stripAndCollapse( value ) {
    var tokens = value.match( rnothtmlwhite ) || [];
    return tokens.join( " " );
  }

To sum up:
You can see that the idea of addClass () is:
(1) Get the current set of class names of elements a
(2) If the class name B to be added does not repeat, add B to a
(3) Final useelem.setAttribute("class",a)complete

Two.$().removeClass
Effect:
Remove the class, if there are no parameters, remove all class names of the target element

Source code:

// Source 8449 lines
    removeClass: function( value ) {
      var classes, elem, cur, curValue, clazz, j, finalValue,
        i = 0;
      // Ibid.
      if ( isFunction( value ) ) {
        return this.each( function( j ) {
          jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
        } );
      }
      // If no parameters are specified, all classes are deleted
      if ( !arguments.length ) {
        return this.attr( "class", "" );
      }
      // Convert (multiple) class names to array form
      classes = classesToArray( value );

      if ( classes.length ) {
        while ( ( elem = this[ i++ ] ) ) {
          curValue = getClass( elem );

          // This expression is here for better compressibility (see addClass)
          cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );

          if ( cur ) {
            j = 0;
            while ( ( clazz = classes[ j++ ] ) ) {
              // If there are classes to be removed from the class name of the current element,
              // Replace this class with ""
              // Remove *all* instances
              while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
                cur = cur.replace( " " + clazz + " ", " " );
              }
            }
            // Ibid.
            // Only assign if different to avoid unneeded rendering.
            finalValue = stripAndCollapse( cur );
            if ( curValue !== finalValue ) {
              elem.setAttribute( "class", finalValue );
            }
          }
        }
      }
      return this;
    },

You can see that the idea of addClass () is:
(1) Get the current set of class names of elements a
(2) If the class name B to be removed does not repeat, replace the B in a with the space “.”
(3) Final useelem.setAttribute("class",a)Complete removing class names

Three.$().toggleClass
Effect:
Switching class

Source code:

// If stateVal is true, classes are added and classes are removed by false.
    // Source 8497 lines
    toggleClass: function( value, stateVal ) {
      var type = typeof value,
        // If value is string type or array type, it is true and vice versa false
        isValidValue = type === "string" || Array.isArray( value );
      // true adds classes, false removes classes
      if ( typeof stateVal === "boolean" && isValidValue ) {
        return stateVal ? this.addClass( value ) : this.removeClass( value );
      }
      // Ibid.
      if ( isFunction( value ) ) {
        return this.each( function( i ) {
          jQuery( this ).toggleClass(
            value.call( this, i, getClass( this ), stateVal ),
            stateVal
          );
        } );
      }

      return this.each( function() {
        var className, i, self, classNames;

        if ( isValidValue ) {

          // Toggle individual class names
          i = 0;
          self = jQuery( this );
          classNames = classesToArray( value );

          while ( ( className = classNames[ i++ ] ) ) {
            // If the target element already has a className for toggle, remove it
            // Check each className given, space separated list
            if ( self.hasClass( className ) ) {
              self.removeClass( className );
            } else {
              // Otherwise, add classes
              self.addClass( className );
            }
          }

          // Toggle whole class name
        }
        // If $. toggleClass () has no value or the value is Boolean
        else if ( value === undefined || type === "boolean" ) {
          className = getClass( this );
          // If the target element has a class, save the class name first with the _className_ attribute
          if ( className ) {

            // Store className if set
            dataPriv.set( this, "__className__", 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.
          // If there is a setAttribute method for the target element
          if ( this.setAttribute ) {
            // If the class name / value = false already exists, remove all class names
            // If there is no class name and value = true,
            // Retrieve the previously saved _className_ as the class name of the target element from dataPriv
            this.setAttribute( "class",
              className || value === false ?
                "" :
                dataPriv.get( this, "__className__" ) || ""
            );
          }
        }
      } );
    },

Analysis:
Mainly two if
(1) if ( typeof stateVal === “boolean” && isValidValue )
Here it is.$()The function of the second parameter of the toggleClass (value, truefalse)
True is addClass (), false is removeClass ()

(2)if(isValidValue )
This is the case where there is only one parameter.
Use hasClass to determine whether to add/remove Class

(3) If $. toggleClass () has no value or the first value is true
If the target element has a class name, usedataPrivTo save the class name,
If the target element hassetAttributeIf so, set the className todataPrivValues saved in.

Four.$().hasClass
Effect:
Check whether the target element contains the specified class

Source code:

// Source code 8568 lines
    hasClass: function( selector ) {
      var className, elem,
        i = 0;

      className = " " + selector + " ";
      while ( ( elem = this[ i++ ] ) ) {
        if ( elem.nodeType === 1 &&
          // Key code
          ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
          return true;
        }
      }

      return false;
    }

This code is quite simple, so it won’t be parsed.


(End)