根据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 );
}
}

jQuery 2.0.3 源码分析 样式操作的更多相关文章

  1. jQuery 2.0.3 源码分析Sizzle引擎解析原理

    jQuery 2.0.3 源码分析Sizzle引擎 - 解析原理 声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 先来回答博友的提问: 如何解析 div > p + ...

  2. jQuery 2.0.3 源码分析 事件绑定 - bind/live/delegate/on

    事件(Event)是JavaScript应用跳动的心脏,通过使用JavaScript ,你可以监听特定事件的发生,并规定让某些事件发生以对这些事件做出响应 事件的基础就不重复讲解了,本来是定位源码分析 ...

  3. jQuery 2.0.3 源码分析 Deferred(最细的实现剖析,带图)

    Deferred的概念请看第一篇 http://www.cnblogs.com/aaronjs/p/3348569.html ******************构建Deferred对象时候的流程图* ...

  4. jQuery 2.0.3 源码分析core - 选择器

         声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢!      打开jQuery源码,一眼看去到处都充斥着正则表达式,jQuery框架的基础就是查询了,查询文档元素对象 ...

  5. jQuery 2.0.3 源码分析 Deferred概念

    JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而回调函数中则包含了后续的工作.这也是造成异步编程困难的主要原因:我们一直习惯于“线性”地编写代码 ...

  6. jQuery 2.0.3 源码分析 事件体系结构

    那么jQuery事件处理机制能帮我们处理那些问题? 毋容置疑首先要解决浏览器事件兼容问题 可以在一个事件类型上添加多个事件处理函数,可以一次添加多个事件类型的事件处理函数 提供了常用事件的便捷方法 支 ...

  7. jQuery 2.0.3 源码分析 Deferrred概念

    转载http://www.cnblogs.com/aaronjs/p/3348569.html JavaScript编程几乎总是伴随着异步操作,传统的异步操作会在操作完成之后,使用回调函数传回结果,而 ...

  8. jQuery 2.0.3 源码分析core - 整体架构

    拜读一个开源框架,最想学到的就是设计的思想和实现的技巧. 废话不多说,jquery这么多年了分析都写烂了,老早以前就拜读过, 不过这几年都是做移动端,一直御用zepto, 最近抽出点时间把jquery ...

  9. jQuery 2.0.3 源码分析Sizzle引擎 - 词法解析

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 浏览器从下载文档到显示页面的过程是个复杂的过程,这里包含了重绘和重排.各家浏览器引擎的工作原理略有差别,但也有一定规则. 简 ...

随机推荐

  1. 【SAP BO】处理掉BOE打开Xcelsius报表时,外围出现的外边框(转)

    原帖地址:http://blog.csdn.net/liyi199488/article/details/8943286 通过BOE打开Xcelsius报表时,总是出现一个外边框. 处理办法: Xce ...

  2. 使用TextUtils.isEmpty简单化代码

    如果让你判断一个文本框是否为空(null)或者没有任何值(length=0),你会怎么怎样去写代码,很多初学者可能会这样写: if(text==null || text.length==0) {... ...

  3. 【Redis】:Jedis 使用

    Redis 支持很多语言, 例如C#,RUBY,JAVA 等, Jedis是redis的java版本的客户端实现 一个简单的Jedis使用 依赖第三方包jedis-2.7.2.jar commons- ...

  4. block 从B界面向A界面传值

    最近在改公司外包项目的代码,发现了一种block传值的用法很有意思,记录一下 A.B两个页面 在B界面.h中定义 @property (nonatomic,strong) void(^block)(N ...

  5. form操作

    1, /* 封装操作表单的常用方法 */ //获取要保存的数据 wjh 2015-10-22 function getSaveData(className) { if (className == nu ...

  6. Redis 的安装与使用(linux)

    官方教程:http://www.redis.io/download 1.下载Redis # wget http://download.redis.io/releases/redis-3.0.4.tar ...

  7. Java中9种IO的读取方式

    数据的读写,按照数据类型可以分为两种:字符流和字节流(二者区别?).所以数据读取方式按照数据类型也可以分为两类:字节流的读取和字符流的读取. 一.字节流读取操作: |  | |-----1.FileI ...

  8. Django实现注册

    前言 对于web开来说,用户登陆.注册.文件上传等是最基础的功能,针对不同的web框架,相关的文章非常多,但搜索之后发现大多都不具有完整性,对于想学习web开发的新手来说不具有很强的操作性:对于web ...

  9. Spring MVC注解的一些案列

    1.  spring MVC-annotation(注解)的配置文件ApplicationContext.xml <?xml version="1.0" encoding=& ...

  10. 用Unity实现时间倒退效果

    记得以前看过一个电影,叫做<独立游戏大电影>,其中有个一个游戏可以实现时间回退的功能,可以像倒带一样,十分有趣.因此我就想着用Unity也实现一个类似的简单Demo,说不定哪天会用到. 效 ...