• jQuery源码分析系列:CSSclass样式


    jQuery提供了4个操作class的方法:

    jQuery.fn.extend({
    	// ...
    	// 为匹配的每个元素增加指定的class(es)
    	addClass: function( value ) {},
    	// 从匹配的每个元素上,移除 一个 或 多个 或 全部class
    	removeClass: function( value ) {},
    	// 对匹配元素集中的每个元素增加或删除一个或多个class
    	toggleClass: function( value, stateVal ) {},
    	// 检测匹配的元素是否指定了传入的class,只要有一个匹配就返回true
    	hasClass: function( selector ) {},
    	// ...
    });

           

    .addClass():
                为匹配的每个元素增加指定的class(es)
                .addClass(className):className添加到每一个匹配元素的class属性上的一个或多个class

                .addClass(function(index,currentClass)):function(index,currentClass)返回一个或多个class名称,多个class用空格分开这些class被添加到现有的class属性中
                index 单签元素在集合中的位置 currentClass 当前的class名     this 指向集合中的当前元素

    .addclass()
            addClass:function(value){
                var classNames,i,l,elem,setClass,c,cl;
                //value为函数
                if(jQuery.isFunction(value)){
                    return this.each(function(j){
                        //this.className 获取当前的class的值
                        jQuery(this).addClass(value.call(this,j,this.className));
                    });
                }
                //vlaue为数组
                if(value && typeof vlaue === "string"){
                    classNames = value.split(rspace);//用空白符风格classNames  转换为数组
    
                    for(i=0,l=this.length;i<l;i++){//遍历所有匹配的元素 缓存长度
                        elem = this[i];//缓存下来 避免再次查找
                        if(elem.nodeType === 1){
                            //如果没有class属性 或class属性为空字符串  classNames.length ===1 ,多于一个去重
                            if(!elem.className && classNames.length === 1){
                                elem.className = value;
                            }else{//已有className 或    classNames长度大于1
    
                                setClass = " " + elem.className + " ";
                                for(c = 0;cl = classNames.length;c<cl:c++){
                                    //不理解
                                    if(!~setClass.indexOf(" " + classNames[c] + " ")){
                                        setClass += classnames[c] + " ";//追加,最后加一个空格
                                    }
                                }
                                //去除首尾空白符
                                elem.className = jQuery.trim(setClass);
                            }
                        }
                    }
                }
            },


    .removeClass():
                从匹配的每个元素上,移除 一个 或 多个 或 全部class

                如果是函数,执行函数,将返回结果再次调用jQuery.fn.removeClass
                如果是字符串,在elem.className和classNames[c]前后加空格,判断replace删除
                如果是undefined,置为空字符串elem.className = ""

                className 一个或多个以空格分隔的class,这些class将被从匹配元素的class属性中移除
                .removeClass( function(index, class) )
                function(index, class) 函数返回一个或多个以空格分隔的class,用于移除。

    .removeClass()
            removeClass:function(value){
                var classNames,i,l,elem,className,c,cl;
                //如果传入函数则执行函数 取返回值作为要移除的classNames
                if(jQuery.isFunction(value)){
                    return this.each(function(j){
                        //this.calssName    获取当前的class值
                        jQuery(this).removeClass(value.call(this,j,this.className));
                    });
                }
                if((value && typeof value === "string") || value === undefined){
                    // value || "" 避免空引用错误的常用技巧
                    classNames = (value || "").split(rspace);//分割数组
    
                    for(i=0,l=this.length;i<l;i++){//遍历所有匹配的元素 缓存长度
                        elem = this[i];//缓存下来 避免再次查找
                        if(elem.nodeType === 1 && elem.className){
                            //如果有value,则从当前className属性中删除
                            if(value){
                                className = (" " + elem.className + " ").replace(rclass," ");//前后加空格 将\n \t \r替换为空格
                                for(c = 0;cl = classNames.length;c<cl:c++){
                                    className = className.replace(" " + classNames[c] + " "," ");//将要删除的className替换为空格
                                }
                                // 删除前后的空白符,然后赋值给elem.className
                                elem.classname = jQuery.trim(className);
                        }else{
                            elem.className = "";
                        }
                    }
                }
                return this;
            },


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

      .toggleClass( className ) 1.0
        className 一个或多个class(用空格隔开),在匹配元素集的每个元素上切换class
         如果集合中的某个元素含有指定的className,className会被删除;如果没有会添加。

      .toggleClass( className, switch ) 1.3
        switch 一个布尔值,依据这个布尔值来决定是添加(true)还是删除(false)

      .toggleClass( [switch] ) 1.4
        switch 一个布尔值,依据这个布尔值来决定是添加还是删除

      .toggleClass( function(index, class, switch) [, switch] ) 1.4
        function(index, class, switch) 函数返回用于切换的calss名称
         index是当前元素是集合中的下标位置, class是当前元素的就class值

      核心技巧:调用addClass 或 removeClass 或 直接赋值elem.className

    .toggleClass()
            toggleClass: function( value, stateVal ) {
                var type = typeof value, // value的类型,可以是字符串(一个或多个class),也可以是function,(undefined和boolean是另说)
                    isBool = typeof stateVal === "boolean";
    
                 // 如果是函数,则执行函数,用函数的返回值作为切换的className,迭代调用jQuery.fn.toggleClass
                if ( jQuery.isFunction( value ) ) {
                    return this.each(function( i ) {
                        // 迭代调用
                        jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
                    });
                }
    
                // 遍历当前jQuery对象
                return this.each(function() {
                    // value是字符串,挨个遍历value中的类样式,switch的优先级高于hasClass,hasClass返回false则addClass返回true则removeClass
                    if ( type === "string" ) {
                        // toggle individual class names
                        // 切换单个class
                        var className,
                            i = 0,
                            self = jQuery( this ),
                            state = stateVal,
                            classNames = value.split( rspace ); // 可能有多个class,用空白符分割
                         // 因为不需要在className前后加空格,所以这里可以将取值、自增、判断合并为while循环。很好的技巧。
                        while ( (className = classNames[ i++ ]) ) {
                            // check each className given, space seperated list
                            /*
                             * 如果state是布尔值,则以state为准,否则检查是否含有className
                             * 含有 state为false,表示需要addClass;反之需要removeClass
                             * 这个三元表达式合并了state与self.hasClass的判断,小技巧
                             */
                            state = isBool ? state : !self.hasClass( className );
                            //删除还是添加
                            self[ state ? "addClass" : "removeClass" ]( className );
                        }
                    /*
                     * type === "undefined"    未指定参数,即.toggleClass()
                     * type === "boolean"     省略className,只有switch,即.toggleClass( switch )
                     */
                    // 未指定参数 或 只有switch,则切换整个className
                    } else if ( type === "undefined" || type === "boolean" ) {
                         // 如果有className,则缓存下来,以便再次调用时恢复
                        if ( this.className ) {
                            // 以内部数据的方式缓存
                            jQuery._data( this, "__className__", this.className );
                        }
    
                        /*
                         * 切换整个className
                         * 又是一个合并了几个判断条件的三元,分解为四个逻辑:
                         * this.className && value 是 true/undefined     ""
                         * this.className && value 是 false             ""
                         * !this.className && value 是 true/undefined    jQuery._data( this, "__className__" ) || ""
                         * !this.className && value 是 false             ""
                         *
                         * 分析一下上边的四个逻辑,可以总结如下:(value用switch代替)
                         * 1. 如果this.className存在,无论switch什么状态(true/false/undefined),都置为空""
                         * 2. 如果this.className不存在,如果switch为true/undefined,才会恢复className
                         * 3. 如果this.className不存在,如果switch为false,置空(保持不变)
                         *
                         * .toggleClass( switch )的用法可以总结如下:
                         * 1. switch为true,进行正常的切换,等价于.toggleClass()
                         * 2. switch为false,总是置空
                         */
                        this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
                    }
                });
            },


    .hasClass():
                检测匹配的元素是否指定了传入的class,只要有一个匹配就返回true
                .hasClass() 检测匹配的元素是否指定了传入的class,只要有一个匹配就返回true;元素可能有多个class,在HTML中多个class用空格隔开;
                如果遇到某个元素含有指定的className,.hasClass()将会返回true,即便还指定了其他的className。

    .hasClass()
            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 + " ").replcae(rclass," ").indexOf(className) > -1){
                        return true;
                    }
                }
                return false;
            }
  • 相关阅读:
    axios
    vue打包之后生成一个配置文件修改请求接口
    微信小程序小结(2) ------ 自定义组件
    eros --- Windows Android真机调试
    weex前端式写法解决方案---eros
    微信小程序小结(1) ------ 前后端交互及wx.request的简易封装
    configparser模块--配置文件
    怎样尊重一个程序员
    poj1326(bfs)
    安装篇——压缩包安装MySql数据库
  • 原文地址:https://www.cnblogs.com/colorstory/p/2630599.html
Copyright © 2020-2023  润新知