`

jQuery乱谈(六)

 
阅读更多

接上一篇:jQuery乱谈(五),今天分析removeClass()、removeProp()、toggleClass()、val()。

 removeClass():

/**
* removeClass方法的内部实现和addClass方法很类似,都是先对参数类型进行判断:
* 参数为Function类型,则利用Function.call()执行函数参数,然后取得返回值,接着
* 利用jQuery.each方法和removeClass方法对每个匹配元素执行命令;
* 参数为String类型,首先对每个匹配元素的class属性的字符串值规则化为
* " class1 class2 class3 "的形式,接着进行各自的处理(移除或添加)
*/
removeClass: function( value ) {
        var removes, className, elem, c, cl, i, l;

        // 如果参数为Function类型,执行该分支语句
        if ( jQuery.isFunction( value ) ) {
            // each方法在jQuery中经常用到,因为我们操作的jQuery对象经常是多个,该方法可以让每个jQuery对象都执行相应的操作
            return this.each(function( j ) { 
                /* 这里用到了Function.call(),这也是在jQuery内部实现中经常用到的
                   还有与之类似的Function.apply()。二者都是用于改变运行上下文,
                   借用已存在的方法进行操作,不同点就是传递参数的方式.
                   这里的value.call(this, j, this.className)会返回一个或更多用空格隔开的被移除class名
        */
                jQuery( this ).removeClass( value.call(this, j, this.className) );
            });
        }
        /**
        只有参数为String或者参数不存在(也可以参数等于undefined),才执行该分支语句
        当参数不存在(也可以参数等于undefined)时,则匹配元素所有的样式类名都会去掉
        */
        if ( (value && typeof value === "string") || value === undefined ) {
            // // core_rspace = /\s+/,用于匹配一个及以上的空白字符 
            removes = ( value || "" ).split( core_rspace ); // 将提供的参数按空白字符分开放到一个数组里

            // // 循环对匹配元素的每一项进行处理
            for ( i = 0, l = this.length; i < l; i++ ) {
                elem = this[ i ]; // 这里的this表示匹配的元素集合,this[ i ]表示匹配的每一项
                // 确保元素是元素节点,而且元素的class属性存在
                if ( elem.nodeType === 1 && elem.className ) {

                    // 在元素原有的class类名字符串前后添加空白字符可以保证添加新的类名后和原来的类名不会连到一块,从而导致错误
                    className = (" " + elem.className + " ").replace( rclass, " " );

                    
                    for ( c = 0, cl = removes.length; c < cl; c++ ) {
                        //  确保新添加的className在原来的元素的class属性中不存在
                        while ( className.indexOf(" " + removes[ c ] + " ") >= 0 ) {
                            // 将要替换的样式类名先处理为“ class1 ”的形式,然后替换为“ ”
                            className = className.replace( " " + removes[ c ] + " " , " " );
                        }
                    }
                    /**
                    jQuery.trim方法用于去除字符串前后空格,如果参数不存在,表明匹配元素的所有样式类名将要全部去掉,所以直接等于"";
                    如果参数存在,且为String类型,则应该去除整个样式类名的前后空格
                    */
                    elem.className = value ? jQuery.trim( className ) : ""; 
                }
            }
        }
        // // 形成链式调用
        return this;
    }

  该方法用于移除每个匹配元素的一个,多个或全部class属性。如果一个样式类名作为一个参数,只有这样式类为匹配的元素集合中被删除 。 如果没有样式名作为参数,那么所有的样式类将被移除。使用方法:

  • removeClass( [ className ] )

    className为每个匹配元素移除的样式属性名。

  • removeClass( function(index, class) )

    function(index, class)这个函数返回一个或更多用空格隔开的被移除样式名。接收元素的索引位置和元素旧的样式名作为参数。

  

  removeProp():

/*
这里用到了propFix: {
        tabindex: "tabIndex",
        readonly: "readOnly",
        "for": "htmlFor",
        "class": "className",
        maxlength: "maxLength",
        cellspacing: "cellSpacing",
        cellpadding: "cellPadding",
        rowspan: "rowSpan",
        colspan: "colSpan",
        usemap: "useMap",
        frameborder: "frameBorder",
        contenteditable: "contentEditable"
    },它用于修正IE浏览器中的IE6、7getAttribute、setAttribute、removeAttribute等方法的不足
*/
removeProp: function( name ) {
        name = jQuery.propFix[ name ] || name;
        return this.each(function() {
            // try/catch 用于处理在IE浏览器中的抽风 (比如移除一个window的属性)
            try {
                /*
                这里的this指的是配一个匹配的元素,我们可以通过this[ name ]访问元素对象的name属性,
                有两种方式来访问对象的属性,点操作符或者中括号操作符。但一般推荐使用中括号操作符,
                因为中括号操作符在下面两种情况下依然有效: 
                动态设置属性;属性名不是一个有效的变量名(比如属性名中包含空格,或者属性名是 JS 的关键词)
                */
                this[ name ] = undefined; // 将 name属性设置成 undefined
                delete this[ name ]; // delete就是用于移除对象的属性
            } catch( e ) {}
        });
    }

  该方法用于为匹配的元素删除设置的属性。只接受一个参数:removeProp( propertyName )。propertyName参数表示要移除的属性名。该方法会移除使用.prop()方法设置的属性。若尝试移除 DOM 元素或window对象上一些内建的 property 属性,浏览器可能会产生错误。如果真的那么做了,那么jQuery首先会将 property 属性设置成undefined,然后忽略任何浏览器产生的错误。一般来说,只需要移除自定义的 property 属性,而不是移除内建的(原生的) property 属性。

注意:不要使用该方法来移除原生的 property 属性,例如:checked, disabled, 或 selected 属性。因为这样会完全移除该 property 属性,它们一旦被删除,就不能再被添加。请使用.prop()来将这些 property 属性的值设置成false

补充说明:

  • 在 IE 9 之前,使用.prop()对一个 DOM 元素的属性进行赋值时,若所赋值的类型不是基本类型(number, string, 或 boolean),而且也没有使用.removeProp()方法在 DOM 元素从文档中被移除之前。为了安全的在 DOM 对象上进行赋值而不用担心内存泄露问题,请使用.data()方法 。

  toggleClass():

toggleClass: function( value, stateVal ) {
        var type = typeof value, // 第一个参数的类型
            isBool = typeof stateVal === "boolean"; // 判断第二个参数是否为boolean型

        // 如果第一个参数为Function类型,执行该分支语句
        if ( jQuery.isFunction( value ) ) {
            // each方法在jQuery中经常用到,因为我们操作的jQuery对象经常是多个,该方法可以让每个jQuery对象都执行相应的操作
            return this.each(function( i ) {
                /* 这里用到了Function.call(),这也是在jQuery内部实现中经常用到的
                   还有与之类似的Function.apply()。二者都是用于改变运行上下文,
                   借用已存在的方法进行操作,不同点就是传递参数的方式.
                   这里的value.call(this, j, this.className, stateVal)会返回在匹配的元素集合中的每个元素上用来切换的样式类名
        */
                jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
            });
        }

        // each方法在jQuery中经常用到,因为我们操作的jQuery对象经常是多个,该方法可以让每个jQuery对象都执行相应的操作
        return this.each(function() {
            // 如果第一个参数为String类型,执行
            if ( type === "string" ) {
                var className,
                    i = 0,
                    self = jQuery( this ),
                    state = stateVal,
                    classNames = value.split( core_rspace );

                while ( (className = classNames[ i++ ]) ) {
                    // 判断每一个class属性值,决定添加还是移除
                    state = isBool ? state : !self.hasClass( className );
                    self[ state ? "addClass" : "removeClass" ]( className );
                }

            } else if ( type === "undefined" || type === "boolean" ) {
                if ( this.className ) {
                    // 如果class属性存在,保存
                    jQuery._data( this, "__className__", this.className );
                }

                // 切换整个class属性,也就是把添加或删除class值后的字符串返回给每个匹配元素的class属性
                this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
            }
        });
    }

  该方法在匹配的元素集合中的每个元素上添加或删除一个或多个样式类,取决于这个样式类是否存在或价值切换属性。即:如果存在(不存在)就删除(添加)一个类。

  • toggleClass( className )

    className在匹配的元素集合中的每个元素上用来切换的一个或多个(用空格隔开)样式类名。

  • toggleClass( className, switch )

    className在匹配的元素集合中的每个元素上用来切换的一个或多个(用空格隔开)样式类名。

    switch一个用来判断样式类添加还是移除的 boolean 值。

  • toggleClass( function(index, class), [ switch ] )

    function(index, class)用来返回在匹配的元素集合中的每个元素上用来切换的样式类名的一个函数。接收元素的索引位置和元素旧的样式类作为参数。

    switch一个用来判断样式类添加还是移除的 boolean 值。如果这个参数的值是true,那么这个样式类将被添加;如果这个参数的值是false,那么这个样式类将被移除。

  val():

val: function( value ) {
        var hooks, ret, isFunction,
            elem = this[0]; // 匹配元素的第一个元素

        // 如果参数不存在,执行该分支语句
        if ( !arguments.length ) { 

            // 保证匹配元素的第一个元素存在
            if ( elem ) {
                /*
                jQuery的val()函数需要针对不同标签进行不同的处理, 因此定义一个以tagName为key的函数映射表
                valHooks: { option: {get:function(){}}} 这样在程序中就不需要到处写:
                if(elm.tagName == ’OPTION’){return …; }else if(elm.tagName == ’TEXTAREA’){ return …;}
                可以统一处理:
                valHooks[elm.tagName.toLowerCase()];
                映射表将函数作为普通数据来管理, 在动态语言中有着广泛的应用.
                */
                // hooks是用来解决浏览器兼容性的问题(select、option等元素)
                hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];

                if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
                    return ret; // ret为获取的值
                }

                ret = elem.value;// 直接获取元素的value值,这时应该主要针对表单元素

                return typeof ret === "string" ?
                    // rreturn = /\r/g,若元素的value值为字符串类型,将字符串中的回车符替换为""
                    ret.replace(rreturn, "") :
                    // 如果value为null,返回"";否则返回ret本身
                    ret == null ? "" : ret;
            }

            return; // 如果值不存在,直接返回
        }



        // 以下代码主要处理参数存在的情况,就是设置值的情况

        isFunction = jQuery.isFunction( value ); // 判断参数是否为Function类型

        return this.each(function( i ) {
            var val,
                self = jQuery(this);

            // 如果节点不是元素节点,直接返回
            if ( this.nodeType !== 1 ) { 
                return;
            }

            // 如果参数为Function类型,val等于函数参数返回的设置的值
            if ( isFunction ) {
                val = value.call( this, i, self.val() );
            } else {// 否则val直接等于参数值
                val = value;
            }

            // 如果val等于null/undefined,val = "";
            if ( val == null ) {
                val = "";
                //  如果val为数字类型,将val值转换为相应的字符串类型
            } else if ( typeof val === "number" ) {
                val += "";
                // 如果val为数组类型,转换为字符串
            } else if ( jQuery.isArray( val ) ) {
                val = jQuery.map(val, function ( value ) {
                    return value == null ? "" : value + "";
                });
            }

            // 同上,hooks是用来解决浏览器兼容性的问题(select、option等元素)
            hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];

            // If set returns undefined, fall back to normal setting
            if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
                this.value = val;
            }
        });
    }

  该方法可以获取匹配的元素集合中第一个元素的当前值,或者设置匹配的元素集合中每个元素的值。val()方法主要用于获取或设置表单元素的值。

  • val()

  获取匹配的元素集合中第一个元素的当前值。

  • val( value )

  设置匹配的元素集合中每个元素的值。

    • val( value )

        value一个文本字符串或一个以字符串形式的数组来设定每个匹配元素的值。

    • val( function(index, value) )

        function(index, value)一个用来返回设置值的函数。

  jQuery的val()方法不仅能够设置元素的值,同时也能获取元素的值。常见的操作是对文本框的操作,比如判断邮箱地址等。val()方法还有另外的一个用处,就是它能使select(下拉列表框),checkbox(多选框)和radio(单选框)相应的项被选中,这在表单操作中经常会用到。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics