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可以实现各种的动画效果。
jQuery 源码分析(十四) 数据操作模块 类样式操作 详解的更多相关文章
- jQuery 源码分析(十二) 数据操作模块 html特性 详解
jQuery的属性操作模块总共有4个部分,本篇说一下第1个部分:HTML特性部分,html特性部分是对原生方法getAttribute()和setAttribute()的封装,用于修改DOM元素的特性 ...
- jQuery 源码分析(十五) 数据操作模块 val详解
jQuery的属性操作模块总共有4个部分,本篇说一下最后一个部分:val值的操作,也是属性操作里最简单的吧,只有一个API,如下: val(vlaue) ;获取匹配元素集合中第一个元素的 ...
- jQuery 源码分析(十九) DOM遍历模块详解
jQuery的DOM遍历模块对DOM模型的原生属性parentNode.childNodes.firstChild.lastChild.previousSibling.nextSibling进行了封装 ...
- Vue.js 源码分析(十九) 指令篇 v-html和v-text指令详解
双大括号会将数据解释为普通文本,而非 HTML 代码.为了输出真正的 HTML,你需要使用 v-html 指令,例如: <!DOCTYPE html> <html lang=&quo ...
- jQuery 源码分析(五) map函数 $.map和$.fn.map函数 详解
$.map() 函数用于使用指定函数处理数组中的每个元素(或对象的每个属性),并将处理结果封装为新的数组返回,该函数有三个参数,如下: elems Array/Object类型 指定的需要处理的数组或 ...
- jQuery 源码分析(十) 数据缓存模块 data详解
jQuery的数据缓存模块以一种安全的方式为DOM元素附加任意类型的数据,避免了在JavaScript对象和DOM元素之间出现循环引用,以及由此而导致的内存泄漏. 数据缓存模块为DOM元素和JavaS ...
- jQuery 源码分析(十六) 事件系统模块 底层方法 详解
jQuery事件系统并没有将事件监听函数直接绑定到DOM元素上,而是基于数据缓存模块来管理监听函数的,事件模块代码有点多,我把它分为了三个部分:分底层方法.实例方法和便捷方法.ready事件来讲,好理 ...
- jQuery 源码分析(十八) ready事件详解
ready事件是当DOM文档树加载完成后执行一个函数(不包含图片,css等),因此它的触发要早于load事件.用法: $(document).ready(fun) ;fun是一个函数,这样当DOM树加 ...
- Vue.js 源码分析(十四) 基础篇 组件 自定义事件详解
我们在开发组件时有时需要和父组件沟通,此时可以用自定义事件来实现 组件的事件分为自定义事件和原生事件,前者用于子组件给父组件发送消息的,后者用于在组件的根元素上直接监听一个原生事件,区别就是绑定原生事 ...
随机推荐
- ABP开发框架前后端开发系列---(14)基于Winform的ABP快速开发框架
前面介绍了很多ABP系列的文章,一步一步的把我们日常开发中涉及到的Web API服务构建.登录日志和操作审计日志.字典管理模块.省份城市的信息维护.权限管理模块中的组织机构.用户.角色.权限.菜单等内 ...
- 并发容器之ConcurrentHashMap(JDK 1.8版本)
1.ConcurrentHashmap简介 在使用HashMap时在多线程情况下扩容会出现CPU接近100%的情况,因为hashmap并不是线程安全的,通常我们可以使用在java体系中古老的hasht ...
- Spring MVC的注解二
概述 Spring从2.5版本开始引入注解,虽然版本不断变化,但是注解的特性一直被延续下来并不断进行扩展,这里就来记录一下Spring MVC中常用的注解,本文承接前文继续记录@PathVariabl ...
- java学习第一步-工欲善其事必先利其器
Java SE 磨刀不误砍柴工,工欲善其事必先利其器,咱们先搞好硬件配置,才能顺利的搞好Java学习 阶段一 1.认识Java 2.java发展史及用户 3.配置Java环境 4.JDK8下载安装 5 ...
- Linux 操作系统的权限为什么是1,2,4 而不是 1,2,3?如何用二进制来做权限管理
1.二进制做权限的优点 大家都知道,在Linux操作系统中,x - 可执行权限,w - 可写权限 , r - 可读权限.其权限值分别是1,2,4,但是有没有想过为什么是1,2,4 而不是 1,2,3 ...
- 【转载】Android App应用启动分析与优化
前言: 昨晚新版本终于发布了,但是还是记得有测试反馈app启动好长时间也没进入app主页,所以今天准备加个班总结一下App启动那些事! app的启动方式: 1.)冷启动 当启动应用时,后台没有该应用 ...
- [20191119]探究ipcs命令输出.txt
[20191119]探究ipcs命令输出.txt $ man ipcsIPCS(8) Linux Programmer's Manual ...
- 读书笔记_python网络编程3(6)
6.TLS/SSL 6.0. 传输层安全协议(TLS, Transport Layer Security)是如今web上应用最广泛的加密方法了,1999年成为互联网标准.前身是安全套接层(SSL, S ...
- 爬取编程常用词汇,保存为Excel
编程常用词汇 import requests import openpyxl from lxml import etree import re url = 'https://www.runoob.co ...
- JVM-6-垃圾回收算法
三如何垃圾回收 GC(Garbage Collection)垃圾回收算法 标记清除 速度快,但是会产生内存碎片: 标记整理 解决了标记清除内存碎片的问题,但是每次都得移动对象,因此成本 ...