zoukankan      html  css  js  c++  java
  • jQuery属性操作(四)

    通过阅读jQuery为属性操作封装的基本方法和为处理兼容性问题提供的hooks,发现jQuery在属性操作方面并没有做过多的设计,只是处理一下兼容性问题,然后调用基础的DOM操作方法。以下是对JQuery提供的基础方法的阅读:

    jQuery.fn.extend({

      // 调用access方法进行参数整理之后调用$.attr方法
        attr: function( name, value ) {
            return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
        },
      // 遍历jQuery对象中的所有元素,对每一个元素调用$.removeAttr方法
        removeAttr: function( name ) {
            return this.each(function() {
                jQuery.removeAttr( this, name );
            });
        },
      // 调用access方法进行参数整理之后调用$.attr方法
        prop: function( name, value ) {
            return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
        },
      // 遍历jQuery对象中的所有元素,直接删除该元素的相应属性
        removeProp: function( name ) {
            return this.each(function() {

        // 对html上的属性和DOM属性进行一些匹配转换
                delete this[ jQuery.propFix[ name ] || name ];
            });
        },
      
        addClass: function( value ) {
            var classes, elem, cur, clazz, j,
                i = 0,
                len = this.length,
                proceed = typeof value === "string" && value;
       // 如果value是function。
            if ( jQuery.isFunction( value ) ) {
                return this.each(function( j ) {

          // 执行该function并将结果作为参数再次调用addClass
                    jQuery( this ).addClass( value.call( this, j, this.className ) );
                });
            }
       // 如果value是字符串
            if ( proceed ) {
                // 如果字符串中有空格,说明添加的不只是一个class,用空格将字符串转换成数组
                classes = ( value || "" ).match( core_rnotwhite ) || [];
         // 遍历jQuery中的每一个DOM元素
                for ( ; i < len; i++ ) {

          // 拿到当前元素
                    elem = this[ i ];

          // 拿到当前元素上的所有当前class
                    cur = elem.nodeType === 1 && ( elem.className ?
                        ( " " + elem.className + " " ).replace( rclass, " " ) :
                        " "
                    );
          // 如果是元素节点(这里看起来像是判断该元素是不是已经有class,其实只是判断是不是元素节点)
                    if ( cur ) {
                        j = 0;

           // 遍历用户传入的所有class
                        while ( (clazz = classes[j++]) ) {

             // 如果当前元素已经有的class中没有用户传入的class,则在已经有的class中增加用户传入的class
                            if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
                                cur += clazz + " ";
                            }
                        }

           // 删除最后得到的class字符串前后两端的空格之后赋值给当前元素的className属性
                        elem.className = jQuery.trim( cur );

                    }
                }
            }

       // 为了实现链式操作,返回this
            return this;
        },
      // 删除class和增加class的逻辑基本一致
        removeClass: function( value ) {
            var classes, elem, cur, clazz, j,
                i = 0,
                len = this.length,
                proceed = arguments.length === 0 || typeof value === "string" && value;

            if ( jQuery.isFunction( value ) ) {
                return this.each(function( j ) {
                    jQuery( this ).removeClass( value.call( this, j, this.className ) );
                });
            }
            if ( proceed ) {
                classes = ( value || "" ).match( core_rnotwhite ) || [];
                for ( ; i < len; i++ ) {
                    elem = this[ i ];
                    cur = elem.nodeType === 1 && ( elem.className ?
                        ( " " + elem.className + " " ).replace( rclass, " " ) :
                        ""
                    );
                    if ( cur ) {
                        j = 0;
                        while ( (clazz = classes[j++]) ) {
                            // 只有此处不同,是从已经有的class中删除用户传入的class
                            while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
                                cur = cur.replace( " " + clazz + " ", " " );
                            }
                        }
                        elem.className = value ? jQuery.trim( cur ) : "";
                    }
                }
            }

            return this;
        },
      // toggleClass是通过调用addClass和removeClass来实现的。 
        toggleClass: function( value, stateVal ) {
            var type = typeof value;
       // stateval是一个boolean值,当为true时,发挥addClass的作用,当为false时,发挥removeClass的作用
            if ( typeof stateVal === "boolean" && type === "string" ) {
                return stateVal ? this.addClass( value ) : this.removeClass( value );
            }
       // 如果是个function,执行之后结果作为参数继续调用toggleClass
            if ( jQuery.isFunction( value ) ) {
                return this.each(function( i ) {
                    jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
                });
            }
       // toggleClass的主体部分
            return this.each(function() {
                if ( type === "string" ) {
                    var className,
                        i = 0,
                        self = jQuery( this ),
                        classNames = value.match( core_rnotwhite ) || [];
          // 遍历所有用户传入的class
                    while ( (className = classNames[ i++ ]) ) {

             // 调用hasClass方法,如果有这个class就删除
                        if ( self.hasClass( className ) ) {
                            self.removeClass( className );

           // 如果没有就添加
                        } else {
                            self.addClass( className );
                        }
                    }
        // 如果用户在调用toggleClass时没有传入class,则对已经有的所有class进行toggle
                } else if ( type === core_strundefined || type === "boolean" ) {
                    if ( this.className ) {
                        // 当删除class时,为了能够在添加回来,将其储存到jQuery内部使用的data对象中
                        data_priv.set( this, "__className__", this.className );
                    }

          // 如果当前元素有class或者没有value(说明没有传value,而是传入了stateVal,这个时候是想要删除class),清空className,否则从缓存中拿出来添      // 加给className属性
                    this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
                }
            });
        },
        hasClass: function( selector ) {
            var className = " " + selector + " ",
                i = 0,
                l = this.length;
            for ( ; i < l; i++ ) {

         // 如果是元素节点,替换掉空格、空行等之后看是否存在用户传入的class
                if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {

          // 如果有,返回true
                    return true;
                }
            }
       // 默认false
            return false;
        },
      // 得到或删除元素值
        val: function( value ) {
            var hooks, ret, isFunction,

         // 只对第一个元素进行操作
                elem = this[0];
         // 如果没有参数,则说明是要取元素值
            if ( !arguments.length ) {
                if ( elem ) {

          // 看看该元素是否有对应的hooks
                    hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
          // 如果有对应的hooks,并且hooks中有get方法,则调用get方法。如果get方法返回了不是undefined的值,则返回该值。
                    if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
                        return ret;
                    }
          // 如果不存在hooks,则正常处理,直接拿到元素的value
                    ret = elem.value;
                    return typeof ret === "string" ?
                        ret.replace(rreturn, "") :
                        ret == null ? "" : ret;
                }
                return;
            }
       // 看参数是否是function
            isFunction = jQuery.isFunction( value );
       // 处理有参数的情况(设置元素值)
            return this.each(function( i ) {
                var val;
        // 如果不是元素节点,直接返回
                if ( this.nodeType !== 1 ) {
                    return;
                }
        // 如果是function,将执行结果赋值个val
                if ( isFunction ) {
                    val = value.call( this, i, jQuery( this ).val() );
                } else {
                    val = value;
                }

        // 如果val为null,则赋值为空字符串
                if ( val == null ) {
                    val = "";

        // 如果是number,转换成字符串
                } else if ( typeof val === "number" ) {
                    val += "";

        // 如果是数组,呃。。
                } else if ( jQuery.isArray( val ) ) {
                    val = jQuery.map(val, function ( value ) {
                        return value == null ? "" : value + "";
                    });
                }
        // 看是否有对应的hooks
                hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
        // 如果没有对应的hooks,或者hooks中没有set方法,或者执行hooks的set方法返回的是undefined(这里其实默默的执行了hooks的set方法)
                if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {

          // 正常赋值
                    this.value = val;
                }
            });
        }
    });

  • 相关阅读:
    Spring boot unable to determine jdbc url from datasouce
    Unable to create initial connections of pool. spring boot mysql
    spring boot MySQL Public Key Retrieval is not allowed
    spring boot no identifier specified for entity
    Establishing SSL connection without server's identity verification is not recommended
    eclipse unable to start within 45 seconds
    Oracle 数据库,远程访问 ora-12541:TNS:无监听程序
    macOS 下安装tomcat
    在macOS 上添加 JAVA_HOME 环境变量
    Maven2: Missing artifact but jars are in place
  • 原文地址:https://www.cnblogs.com/charling/p/3498531.html
Copyright © 2011-2022 走看看