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;
                }
            });
        }
    });

  • 相关阅读:
    centos7安装rabbitmq 总结
    python第六十三天-- 第十一周作业
    python第六十一天,第六十二天 redis
    python第六十天-----RabbitMQ
    python第五十四天--第十周作业
    python第五十三天--进程,协程.select.异步I/O...
    python第五十二天---第九周作业 类 Fabric 主机管理程序
    python第五十一天----线程,Event,队列
    Python基础之-面向对象编程(引言)
    Python中的模块
  • 原文地址:https://www.cnblogs.com/charling/p/3498531.html
Copyright © 2011-2022 走看看