根据API分类

CSS


.addClass()

对元素的样式操作,底层的实现就是修改元素的className值

实现的功能:

增加一条样式规则: .addClass(‘myClass’)

增加多条样式规则: .addClass(‘myClass yourClass’)

传递回调遍历样式规则:

$("ul li:last").addClass(function(index) {
  return "item-" + index;
});

从接口传参去分析这个实现手法:

源码:

addClass源码        // 为匹配的每个元素增加指定的class(es)
        addClass: function( value ) {
            var classes, elem, cur, clazz, j,
                i = 0,
                len = this.length,
                proceed = typeof value === "string" && value;

            //如果传递的是回调函数,递归调用  ⑴
            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)
                //分解下样式规则,通过正则/\S+/g 空白分组
                // classes [
                //    0: "highlight"
                // ]                               ⑵
                classes = ( value || "" ).match( core_rnotwhite ) || [];

                for ( ; i < len; i++ ) {
                    elem = this[ i ];
                    //如果元素本身存在class样式,先取出来     ⑷
                    cur = elem.nodeType === 1 && ( elem.className ?
                        ( "" + elem.className + "" ).replace( rclass, "" ) :
                        ""
                        );

                    if ( cur ) {  //组合成新的规则按照空格分开  ⑸
                        j = 0;
                        while ( (clazz = classes[j++]) ) {
                            if ( cur.indexOf( "" + clazz + "" ) < 0 ) {
                                cur += clazz + "";
                            }
                        }
                        //设置样式  ⑹
                        elem.className = jQuery.trim( cur );

                    }
                }
            }

            return this;
        },

我把代码简略的分了5个步骤

  • 如果传递的是回调函数,递归调用
  • 分解下样式规则,通过正则/\S+/g 空白分组
  • 如果元素本身存在class样式,先取出来
  • 组合成新的规则按照空格分开
  • 通过className 设置新的样式

传递一个参数与多个参数的处理无非就是字符串的拼接,这里就不详讲,看看代码就能理解

重点说一下传递回调函数的设计

官方给的测试案例

HTML结构

<p class ='selected highlight'>Goodbye</p>
<p class ='selected1 highlight1'>Goodbye</p>
<p class ='selected2 highlight2'>Goodbye</p>

增加样式代码

$(p).addClass(function(index,className){
//        index  className
//        0 "selected highlight"
//        1 "selected1 highlight1"
//        2 "selected2 highlight2"
    });

遍历出所有的P节点,并找其对应的class,返回给每一个回调函数

看看源码的设计

//如果传递的是回调函数,递归调用  ⑴
if ( jQuery.isFunction( value ) ) {
    return this.each(function( j ) {   //each addClass回调
        jQuery( this ).addClass( value.call( this, j, this.className ) );
    });
}

不管是写插件还是其他的,只要是设计操作DOM的在jQuery内部就的到 this.each方法

原因很简单,jQuery就是一个数组保存着所有对应的节点的下标

内部在传递一个编写好的回调函数,传递给each方法

each方法理解就是一个循环方法,分解出jQuery数组中每一个下标元,然后把每一个元素返回给外部回调

这里在进步替换下代码就很明显了

function(  i, obj[ i ]  ) {   //each addClass回调
        jQuery( this ).addClass( value.call( this, j, this.className ) );
 }

这里的this是指向的每一个p元素节点,因为callback.call了一下,把每一个上下文指定到当前的函数了,所以this就是对应的obj[i]

最后执行的代码就是

value.call( this, j, this.className )

value就是最外层用户定义的回调了

$(p).addClass(function(index,className){
//        index  className
//        0 "selected highlight"
//        1 "selected1 highlight1"
//        2 "selected2 highlight2"
    });

这里意外的发现jQuery Api没给出

还包装了一层jQuery( this ).addClass

那么意味着,jQuery还可以接受用户最外层的返回参数,然后再调用addClass给当前节点增加新的类名

jQuery( this ).addClass( value.call( this, j, this.className ) );
p.addClass(function(index,className){
        return 'aaaa'
    });


.removeClass( [className ] )

代码跟结构与addClass很相似

removeClass源码        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;
        },

.hasClass

.hasClass() 检测匹配的元素是否指定了传入的class,只要有一个匹配就返回true

元素可能有多个class,在HTML中多个class用空格隔开;

如果遇到某个元素含有指定的className,.hasClass()将会返回true,即便还指定了其他的className。

/**
* 检测匹配的元素是否指定了传入的class,只要有一个匹配就返回true
 * .hasClass( className )
 *   className 要查找的class
* 核心技巧:前后加空格 + indexOf
 */
hasClass: function( selector ) {
    var className = " " + selector + " ", // 前后加空格
        i = 0,
        l = this.length;
    for ( ; i < l; i++ ) {
         // 必须是Element,技巧同样是前后加空格,同样是indexOf
        if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
            return true;
        }
    }

    return false;
},

jQuery.cssHooks

http://www.css88.com/jqapi-1.9/jQuery.cssHooks/

关于jQuery的钩子,单独暴露的一个接口,然用户可以自定义兼容

http://www.cnblogs.com/aaronjs/p/3387906.html 文章已经说了原理


.toggleClass()

.toggleClass() 负责对匹配元素集中的每个元素增加或删除一个或多个class,增加或删除的行为依赖当前元素是否含有指定的class或switch参数的值

.toggleClass()接受一个或多个class;自从jQuery1.4以后,如果没有为.toggleClass()指定参数,元素上的所有class名称将被切换;

自从jQuery1.4以后,className可以是一个函数,函数的返回值作为切换的className。

通过判断节点上是否有className从而实现切换

结合了hasClass,addClass,removeClass

while ( (className = classNames[ i++ ]) ) {
    // check each className given, space separated list
    if ( self.hasClass( className ) ) {
        self.removeClass( className );
    } else {
        self.addClass( className );
    }
}

随机推荐

  1. Android中的内容提供器

    用途 不同于File, SharedPreferences和DataBase,Content Provider主要用于不同的应用程序间共享数据,允许一个程序安全的访问另一个程序中的数据. 用法 通过C ...

  2. struts2 Result Type四个常用转跳类型

    Result的四个常用转跳类型分别为 Dispatcher 用来转向页面,是Struts的默认形式 Redirect   重定向到一个URL Chain  用来处理Action链 RedirectAc ...

  3. Java的递归算法

    递归算法设计的基本思想是:对于一个复杂的问题,把原问题分解为若干个相对简单类同的子问题,继续下去直到子问题简单到可以直接求解,也就是说到了递推的出口,这样原问题就有递推得解. 关键要抓住的是: (1) ...

  4. WinAPI——模拟正弦波

    /*************************** * * 程序名称 : 模拟正弦波 * 作 者 : doodle777 * 版 本 : 1.1 * 日 期 : 2012-10-19 * 说 明 ...

  5. 关于时间,日期,星期,月份的算法(Java中Calendar的用法)(一)

    package cn.outofmemory.codes.Date; import java.util.Calendar; import java.util.Date; public class Ca ...

  6. c# 用正则表达式在指定的字符串中每隔指定个数的文字插入指定字符串

    public static string AddNewLine(string inString,int num,string addString="\r\n") { return ...

  7. Git提交到多个远程仓库

    在已经习惯使用git同步写代码,github无疑是最的托管平台,但是国内由于"你懂的"原因,速度很慢,有时无法访问,于是想把自己的代码同步到多个不同的远程仓库备份. 我的主要仓库: ...

  8. SQL语句原理解析(原创)

    基本的sql语句很好理解这里不做分析,这里只考虑复杂的sql语法和关键词用法的实验分析: 一,join关联的作用: 作用: 1,为了生成信息信息更加全面的中间表:2,为了where可以使用含有单表外字 ...

  9. python3.6利用pyinstaller模块打包程序为.exe可执行程序

    步骤: 1.安装pyinstaller模块:(必须在联网情况下进行) 操作原理: python3.6已经自带了pip,所以只需要在cmd中执行 pip install pyinstaller 就可以安 ...

  10. Pycharm(三)常用设置

    File - Settings (ctrl+alt+s) python模板 Editor - File and Code Templates - Python Script 可以使用部分变量. # ! ...