jQuery 源码分析(十四) 数据操作模块 类样式操作 详解
jquery的属性操作模块总共有4个部分,本篇说一下第3个部分:类样式操作部分,用于修改dom元素的class特性的,对于类样式操作来说,jquery并没有定义静态方法,而只定义了实例方法,如下:
- addclass(value) ;为匹配元素集合中的每个元素添加一个或多个类样式,通过修改dom属性classname来修改类样式,value可以是个以空格分隔的类样式或者一个函数(返回一个或多个以空格分隔的类样式)
- hasclass(selector) ;检测匹配元素中的任意元素是否含有指定的类样式,只要其中一个元素含有就返回true,selector是一个类样式。
- removeclass(value) ;从匹配元素集合中的每个元素上移除一个或多个或全部类样式,value可以为空(全部移除)、以空格分隔的类样式(移除多个样式),或者是个函数(该函数返回一个或多个以空格分隔的类样式)
- toggleclass(value,stateval) ;对设置或移除被选元素的一个或多个类进行切换,有五种用法
writer by:大沙漠 qq:22969969
·toggleclass() ;未传入参数 ;这时如果当前元素含有样式则移除所有类,如果没有则尝试恢复。
·toggleclass(stateval) ;只传入一个布尔值类型 ;如果stateval是true,则等同于toggleclass();如果是false则总是移除所有类。
·toggleclass(value) ;参数1是字符串或函数,未传入参数2 ;value是字符串时表示一个或多个样式,用空格分隔,下同;value是函数时返回字符串格式。如果匹配元素含有指定的类样式,则移除,否则添加该样式。
·toggleclass(value,stateval) ;参数1是字符串或函数,参数2是布尔值 ;当stateval是true时总是添加,是false时则总是移除
对于toggleclass切换样式时,jquery内部实现会将所有类暂时保存在数据缓存对象的__classname__数据中,等下次恢复时尝试读取。
举个栗子吧:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>document</title> <script src="http://libs.baidu.com/jquery/1.7.1/jquery.min.js"></script> <style> .color{color: #f00;} .back{background: #ccc;} </style> </head> <body> <p>hello world!</p> <button id="b1">设置所有样式</button> <button id="b2">切换color样式</button> <button id="b3">取消所有样式</button> <script> let b1 = document.getelementbyid('b1'), b2 = document.getelementbyid('b2'), b3 = document.getelementbyid('b3'); b1.onclick = ()=>{ $('p').addclass('color back'); //添加所有样式 } b2.onclick = ()=>{ $('p').toggleclass('color'); //切换color样式 } b3.onclick = ()=>{ $('p').removeclass(); //取消所有样式 } </script> </body> </html>
这里我们在style自定义了两个class:color和back,前者修改字体的颜色,后者修改字体的背景色,然后定义了三个按钮分别用于操作样式,渲染如下:
点击设置所有样式,将在p这个dom元素上添加color和back两个class,如下:
当点击切换color样式时,由于p元素上的color这个class已经存在了,因此会取消掉:
当再次点击切换color样式这个按钮时,由于p元素上的color这个class已经取消了,因此此时会显示出来,如下:
当我们点击取消所有样式时将会把p元素上的所有class给删掉,又回到初始状态,如下:
源码分析
jquery内部对于样式的操作是修改对应dom元素的classname属性来实现的,中间通过字符串的indexof和replace操作实现查找和替换,对于添加样式和删除样式的逻辑如下:
jquery.fn.extend({ addclass: function( value ) { //添加类样式 var classnames, i, l, elem, setclass, c, cl; if ( jquery.isfunction( value ) ) { //如果value是函数 return this.each(function( j ) { jquery( this ).addclass( value.call(this, j, this.classname) ); //在每个匹配元素上执行该函数并且取其返回值作为待添加的类样式,然后调用.addclass(classname)添加类样式。执行函数时,传入两个参数,分别是元素在集合中的下标位置和当前样式值。 }); } if ( value && typeof value === "string" ) { //如果value是字符串,可以是空格分隔的多个样式 classnames = value.split( rspace ); //用/\s+/对value进行分隔 for ( i = 0, l = this.length; i < l; i++ ) { //遍历匹配元素 elem = this[ i ]; if ( elem.nodetype === 1 ) { //只针对元素节点 if ( !elem.classname && classnames.length === 1 ) { //如果elem.classname不存在,且待添加的样式个数为1,则直接设置elem.classname elem.classname = value; } else { setclass = " " + elem.classname + " "; //在待添加的类样式classname前后加空格 for ( c = 0, cl = classnames.length; c < cl; c++ ) { //历要添加的类样式value if ( !~setclass.indexof( " " + classnames[ c ] + " " ) ) { //如果classnames中的某个样式不存在setclass中 setclass += classnames[ c ] + " "; //则添加该样式 } } elem.classname = jquery.trim( setclass ); //最后去除类样式两边的空格,再设置到elem.classname中 } } } } return this; }, removeclass: function( value ) { //从匹配元素集合中的每个元素上移除一个或多个或全部类样式。通过修改dom属性classname来移除类样式。 var classnames, i, l, elem, classname, c, cl; if ( jquery.isfunction( value ) ) { //如果value是一个函数 return this.each(function( j ) { //遍历匹配元素 jquery( this ).removeclass( value.call(this, j, this.classname) ); //调用每个匹配元素的removeclass()函数,参数是value函数的返回值 }); } if ( (value && typeof value === "string") || value === undefined ) { //如果value存在且是一个字符串 或者 value未定义 classnames = ( value || "" ).split( rspace ); //用空白符分隔value以支持一次移除多个类样式。这里如果value是空的,那么结果是[""],该数组的length等于1 for ( i = 0, l = this.length; i < l; i++ ) { //遍历匹配元素 elem = this[ i ]; //elem是匹配的元素 if ( elem.nodetype === 1 && elem.classname ) { //只支持已经设置了classname的元素节点。 if ( value ) { //如果传入了value值,则表示是设置样式 classname = (" " + elem.classname + " ").replace( rclass, " " ); //classnames是当前元素的类样式,两边加个空格,再去除出换行、制表、回车符。var rclass = /[\n\t\r]/g, for ( c = 0, cl = classnames.length; c < cl; c++ ) { //遍历要移除的类样式数组classnames classname = classname.replace(" " + classnames[ c ] + " ", " "); //调用字符串方法replace()逐个从当前类样式中移除 } elem.classname = jquery.trim( classname ); //去掉空白字符,在设置elem.classname属性 } else { elem.classname = ""; } } } } return this; }, /*略*/ })
当我们在页面里做各种动画效果时还是会用到这个api的,挺方便的,配合css可以实现各种的动画效果。
上一篇: 设计模式之策略模式
下一篇: python犯傻之题目解答思路比较与反思
推荐阅读
-
jQuery 源码解析(二十九) 样式操作模块 尺寸详解
-
jQuery 源码分析(十三) 数据操作模块 DOM属性 详解
-
jQuery 源码解析(二十七) 样式操作模块 坐标详解
-
jQuery 源码分析(十二) 数据操作模块 html特性 详解
-
jQuery 源码解析(二十四) DOM操作模块 包裹元素 详解
-
jQuery 源码分析(二十一) DOM操作模块 删除元素 详解
-
jQuery 源码解析(二十六) 样式操作模块 样式详解
-
jQuery 源码分析(十五) 数据操作模块 val详解
-
jQuery 源码解析(二十八) 样式操作模块 scrollLeft和scrollTop详解
-
jQuery 源码分析(二十) DOM操作模块 插入元素 详解