资讯专栏INFORMATION COLUMN

jQuery源码解析之addClass(),removeClass(),toggleClass()和

Aceyclee / 954人阅读

摘要:四作用检查目标元素是否包含指定的类源码源码行关键代码这个代码还挺简单的,就不解析了。

一、$().addClass()
作用:
向目标元素添加一个或多个类名

源码:

    //向目标元素添加一个或多个类名
    //源码8401行
    addClass: function( value ) {
      var classes, elem, cur, curValue, clazz, j, finalValue,
        i = 0;
      //如果addClass(value)的value是一个function
      //那么就通过call让目标元素this调用该function
      if ( isFunction( value ) ) {
        return this.each( function( j ) {
          // function(index,currentclass)
          // index 对应 j,作用是获取多个目标元素的下标;
          // currentClass 对应 getClass(this),作用是获取当前元素的类名,方便加空格
          jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
        } );
      }
      //将(多个)类名转为数组形式
      classes = classesToArray( value );
      if ( classes.length ) {
        //多个目标元素
        while ( ( elem = this[ i++ ] ) ) {
          //获取当前值
          curValue = getClass( elem );
          //如果目标元素是元素节点并且用空格左右包起来 " "+value+" "
          cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );

          if ( cur ) {
            j = 0;
            //一个个类名
            while ( ( clazz = classes[ j++ ] ) ) {
              //当前元素没有和要添加的类名重复的话就添加
              if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
                cur += clazz + " ";
              }
            }
            //最后,确认经过处理后的类名集合是否和处理前的类名集合相同
            //如果相同,就setAttribute,重新渲染,否则不重新渲染(性能优化)
            // Only assign if different to avoid unneeded rendering.
            finalValue = stripAndCollapse( cur );
            if ( curValue !== finalValue ) {
              //最后通过setAttribute,添加类名
              elem.setAttribute( "class", finalValue );
            }
          }
        }
      }
      return this;
    },

解析:
(1)getClass()
作用:
获取目标元素的类名

源码:

  //源码8377行
  function getClass( elem ) {
    return elem.getAttribute && elem.getAttribute( "class" ) || "";
  }

(2)classesToArray
作用:
将(多个)类名转为数组形式

源码:

  //源码8382行
  function classesToArray( value ) {
    //元素的className如果有多个类名的话,是以数组形式保存的,那就直接返回
    if ( Array.isArray( value ) ) {
      return value;
    }
    //如果元素类名是string类型的话
    if ( typeof value === "string" ) {
      return value.match( rnothtmlwhite ) || [];
    }
    return [];
  }

(3)stripAndCollapse
作用:
将vaues以空格分开,再以空格拼接

源码:

  // 源码8370行
  // 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( " " );
  }

综上:
可以看到 addClass() 的思路是:
① 获取元素当前类名集合 a
② 如果要添加的类名 b 不重复,则将 b 添加进 a 里
③ 最后使用elem.setAttribute("class",a)完成

二、$().removeClass
作用:
移除类,如果没有参数,则移除目标元素所有类名

源码:

    //源码8449行
    removeClass: function( value ) {
      var classes, elem, cur, curValue, clazz, j, finalValue,
        i = 0;
      //作用同上
      if ( isFunction( value ) ) {
        return this.each( function( j ) {
          jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
        } );
      }
      //如果没有规定参数,则删除所有类
      if ( !arguments.length ) {
        return this.attr( "class", "" );
      }
      //将(多个)类名转为数组形式
      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++ ] ) ) {
              // 如果当前元素的类名里有要移除的类,
              // 就将该类替换成" "
              // Remove *all* instances
              while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
                cur = cur.replace( " " + clazz + " ", " " );
              }
            }
            //同上
            // Only assign if different to avoid unneeded rendering.
            finalValue = stripAndCollapse( cur );
            if ( curValue !== finalValue ) {
              elem.setAttribute( "class", finalValue );
            }
          }
        }
      }
      return this;
    },

可以看到 addClass() 的思路是:
① 获取元素当前类名集合 a
② 如果要移除的类名 b 不重复,则将 a 里面的 b 替换成空格 " "
③ 最后使用elem.setAttribute("class",a)完成移除类名

三、$().toggleClass
作用:
切换类

源码:

    //stateVal为true,则添加类,false则移除类
    //源码8497行
    toggleClass: function( value, stateVal ) {
      var type = typeof value,
        //如果value是string类型或者是数组类型的话,为true,反之为false
        isValidValue = type === "string" || Array.isArray( value );
      //true添加类,false移除类
      if ( typeof stateVal === "boolean" && isValidValue ) {
        return stateVal ? this.addClass( value ) : this.removeClass( value );
      }
      //同上
      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++ ] ) ) {
            //如果目标元素已经有要toggle的className,那么就移除它
            // Check each className given, space separated list
            if ( self.hasClass( className ) ) {
              self.removeClass( className );
            } else {
              //否则就添加类
              self.addClass( className );
            }
          }

          // Toggle whole class name
        }
        //如果$.toggleClass()没有值或者该值为布尔值
        else if ( value === undefined || type === "boolean" ) {
          className = getClass( this );
          //如果目标元素有类的话,就先用__className__属性保存类名
          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.
          //如果目标元素存在setAttribute的方法话
          if ( this.setAttribute ) {
            //如果已有类名/value=false,则移除所有类名
            //如果没有类名并且value=true,
            //则从dataPriv中重新获取之前保存过的__className__当做目标元素的类名
            this.setAttribute( "class",
              className || value === false ?
                "" :
                dataPriv.get( this, "__className__" ) || ""
            );
          }
        }
      } );
    },

解析:
主要是两个 if
(1) if ( typeof stateVal === "boolean" && isValidValue )
这个就是$().toggleClass(value,truefalse) 的第二个参数的作用了,
true 即 addClass(),false 即 removeClass()

(2)if(isValidValue )
这个是只有一个参数的情况
利用 hasClass 判断是否 add/removeClass

(3)如果$.toggleClass()没有值或者第一个值为 true 的话
如果目标元素有类名的话,就使用dataPriv来保存类名,
如果目标元素有setAttribute的话,则将 className 设置为dataPriv里保存的值。

四、$().hasClass
作用:
检查目标元素是否包含指定的类

源码:

    //源码8568行
    hasClass: function( selector ) {
      var className, elem,
        i = 0;

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

      return false;
    }

这个代码还挺简单的,就不解析了。

(完)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/109807.html

相关文章

  • jQuery 源码系列(十八)class 相关操作

    摘要:眼看的源码就快到头了,后面还有几个重要的内容,包括和动画操作,加油把它们看完,百度前端学院的新一批课程也开始了。,当第二个参数为的情况,就是,为时,,从源码来看,就是直接调用的这两个函数。参考源码分析样式操作本文在上的源码地址,欢迎来。 欢迎来我的专栏查看系列文章。 眼看 jQuery 的源码就快到头了,后面还有几个重要的内容,包括 ajax 和动画操作,加油把它们看完,百度前端学院的...

    BingqiChen 评论0 收藏0
  • jquery梳理属性操作

    摘要:与元素属性原生对于元素的属性有三种方法来操作为元素添加属性名和属性值获取元素属性值删除元素属性而则将以上三个操作简化为和对应对应对应上述的为属性名,为属性值对于需要设置多个属性时,采用的方式是在方法传入属性配置对象元素值属性三个方法都 attr与removeAttr - 元素属性 JS原生对于元素的属性有三种方法来操作 dom.setAttribute(name , value) //...

    silencezwm 评论0 收藏0
  • jQuery 属性与样式

    摘要:与中用方法来获取和设置元素属性是属性的缩写,在操作中会经常用到有个表达式传入属性名获取属性的值属性名属性值设置属性的值属性名函数值设置属性的函数值给指定元素设置多个属性值,即属性名一属性值一属性名二属性值二删除方法为匹配的元素集合中的每个元 .attr()与.removeAttr() jQuery中用attr()方法来获取和设置元素属性,attr是attribute(属性)的缩写,在j...

    yibinnn 评论0 收藏0
  • jQuery入门笔记(二)文档对象模型

    摘要:删除指定的属性,这个方法就不可以使用匿名函数,传递和均无效。遍历对象数组索引,鍵,属性名属性值,值相当于遍历原生对象数组时,为元素。在使用使用时,可以使用传入匿名函数的方法,实现由默认到几个之间的切换。 转自个人博客 基础 DOM 和 和 CSS 一. 设置元素及内容 我们通过前面所学习的各种选择器、过滤器来得到我们想要操作的元素。这个时候,我们就可以对这些元素进行 DOM 的操作。...

    FleyX 评论0 收藏0
  • jQuery基础(一) :样式篇

    摘要:如下就是对象或是如下以下两者的修改都是等价的但是使用不能很好的操作,所以可以将其转换成对象把元素转化成的对象总体,表示当前的上下文对象是一个对象,可以调用对象所拥有的属性和方法。代表的上下文对象是一个的上下文对象,可以调用的方法和属性值。 一:初识 jquery: 1、 jQuery 只是一个库,不需要特别的安装,只需要我们在页面 标签内中通过 script 标签脚本引入 jQuer...

    SegmentFault 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<