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可以实现各种的动画效果。

原文地址:https://www.cnblogs.com/greatdesert/p/11672871.html

时间: 2024-09-27 04:29:21

jQuery 源码分析(十四) 数据操作模块 类样式操作 详解的相关文章

jQuery 源码分析(十五) 数据操作模块 val详解

jQuery的属性操作模块总共有4个部分,本篇说一下最后一个部分:val值的操作,也是属性操作里最简单的吧,只有一个API,如下: val(vlaue)        ;获取匹配元素集合中第一个元素的当前值,或者设置匹配元素集合中每个元素的值,有三种用法: val()        ;没有参数,获取第一个匹配元素的当前值 val(value)      ;为每个匹配元素设置value值        ;如果为null则表示设置值为空 val(func)       ;设置每个匹配元素为函数fun

jQuery 源码分析(十九) DOM遍历模块详解

jQuery的DOM遍历模块对DOM模型的原生属性parentNode.childNodes.firstChild.lastChild.previousSibling.nextSibling进行了封装和扩展,用于在DOM树中遍历父元素.子元素和兄弟元素. 可以通过jQuery的实例来访问,方法如下: parent()             ;获取匹配元素的父元素 parents(selector)         ;获取匹配元素的所有祖先元素                        ;s

jQuery 源码分析(十八) ready事件详解

ready事件是当DOM文档树加载完成后执行一个函数(不包含图片,css等),因此它的触发要早于load事件.用法: $(document).ready(fun) ;fun是一个函数,这样当DOM树加载完毕后就会执行该匿名函数了 ready有一个简写,可以直接传入$(fun)即可,这是因为在jQuey内部也定义了一个$(document)的jQuery对象,和我们在上面的写法是一样的 ready事件和window的onload区别: ready事件 ;等dom树载完毕后就可以执行 onload事

[转]jQuery源码分析系列

文章转自:jQuery源码分析系列-Aaron 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://github.com/JsAaron/jQuery 正在编写的书 - jQuery架构设计与实现 本人在慕课网的教程(完结) jQuery源码解析(架构与依赖模块) 64课时 jQuery源码解析(DOM与核心模块)64课时 jQuery源码分析目录(完结) jQuery源码分析系列(01) : 整体架构 jQuery源码分析系列(

jQuery源码分析系列(38) : 队列操作

Queue队列,如同data数据缓存与Deferred异步模型一样,都是jQuery库的内部实现的基础设施 Queue队列是animate动画依赖的基础设施,整个jQuery中队列仅供给动画使用 Queue队列 队列是一种特殊的线性表,只允许在表的前端(队头)进行删除操作(出队),在表的后端(队尾)进行插入操作(入队).队列的特点是先进先出(FIFO-first in first out),即最先插入的元素最先被删除. 为什么要引入队列? 我们知道代码的执行流有异步与同步之分,例如 var a

Jquery源码分析

1.概述 jQuery是一个非常优秀的Js库,与prototype,YUI,Mootools等众多的Js类库相比,它剑走偏锋,从web开发最实用的角度出发,抛除了一些中看但不实用的东西,为开发者提供一个短小精悍的类库.由于其个短小精悍,使用简单方便,性能相对高效.众多的开发者都选择Jquery来进行辅助的web开发. 在使用jquery时开发,我们也会时常碰到许多的问题,但是jquery的代码很晦涩,难起看懂,当开发时出现了问题,看不懂源码,不知道如何去排错. John Resig,Jquery

jquery源码分析(二)——结构

再来复习下整体架构: jQuery源码分析(基于 jQuery 1.11 版本,共计8829行源码) (21,94)                定义了一些变量和函数jQuery=function(){} (96,280)        给jQuery添加一些方法和属性,jQuery.fn=jQuery.prototype(285,347)        extend:        jQuery的一些继承方法        更容易进行后续的扩展                       

jQuery源码分析系列(39) : 动画队列

data函数在jQuery中只有短短的300行代码,非常不起点 ,剖析源码的时候你会发现jQuery只要在有需要保存数据的地方无时无刻不依赖这个基础设施 动画会调用队列,队列会调用data数据接口还保存队列里面的的动画数据 所以我们在自习回顾下关于数据缓存 //These may be used throughout the jQuery core codebase //存数据的 //用户使用 data_user = new Data(); //存储对象 //jQuery内部私有 //用来存事件

jQuery源码分析系列(31) : Ajax deferred实现 - Aaron.

AJAX的底层实现都是浏览器提供的,所以任何基于api上面的框架或者库,都只是说对于功能的灵活与兼容维护性做出最优的扩展 ajax请求的流程: 1.通过 new XMLHttpRequest 或其它的形式(指IE)生成ajax的对象xhr. 2.通过xhr.open(type, url, async, username, password)的形式建立一个连接. 3.通过setRequestHeader设定xhr的请求头部(request header). 4.通过send(data)请求服务器端