• jQuery属性操作之.attr()


    转载请注明出处

    @[toc] # .attr() 1.**.attr()**的四种用法 大致用法:
    • 调用形式:$("xxx").attr(attrName);
      获取匹配到的所有元素中的第一个元素的指定属性的属性值.
    • 调用形式:$("xxx").attr(attrName,value):
      • 设置/新增匹配到的所有元素的指定属性的属性值
      • 如果value=null,指定属性将被删除
    • 调用形式:$("xxx").attr(attrObject):
      用"属性-值"的键值对构成的对象来设置匹配到的所有元素的一个或多个属性.
    • 调用形式:$("xxx").attr(attrName,attrFn(index,val)):
      用一个函数attrFn的返回值作为value来设置某一个匹配元素的指定属性.(attrFn函数的参数有明确规定:index--该匹配元素在jQuery对象中的index值,也就是它的键值.attr--当前该元素的该属性的值(旧值))

    用法详解:
    (1)..attr()源代码定义:

    jQuery.fn.extend( {
    	attr: function( name, value ) {
    		return access( this, jQuery.attr, name, value, arguments.length > 1 );
    	}
    }
    

    可见,.attr的核心是函数access(),而该函数不需要实例即可调用,属于直接定义在jQuery上的'静态函数'.

    jQuery.access()源代码定义:

    var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
    	var i = 0,
    		length = elems.length,
    		bulk = key == null; //bulk用于判断key值是否为null(注:null==undefined的结果为true)
    
    	// 设置多个值(当key参数为对象时,注:jQuery.type实现原理是[[class]])
    	if ( jQuery.type( key ) === "object" ) {
    		chainable = true;
    		for ( i in key ) {
    			access( elems, fn, i, key[ i ], true, emptyGet, raw );
    		}
    
    	// 设置一个值(当key为非对象类型时)
    	} else if ( value !== undefined ) {
    		chainable = true;
    
    		if ( !jQuery.isFunction( value ) ) {
    			raw = true; //判断value值是否为函数类型.如果不是函数,设置raw值,为if(fn)以及if(bulk)埋下伏笔
    		}
    
    		if ( bulk ) { //批处理
    
    			// 批处理是执行在整个属性集上的
    			if ( raw ) {
    				fn.call( elems, value );
    				fn = null;
    
    			// 当value为函数时又有点不同
    			} else {
    				bulk = fn;
    				fn = function( elem, key, value ) {
    					return bulk.call( jQuery( elem ), value );
    				};
    			}
    		}
    
    		if ( fn ) { //对elems中的每一个元素应用fn方法,第三个参数由raw决定
    			for ( ; i < length; i++ ) {
    				fn(
    					elems[ i ],
    					key,
    					raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) )
    				);
    			}
    		}
    	}
    
    	return chainable ? //返回值设定
    		elems :
    
    		// Gets
    		bulk ?
    			fn.call( elems ) :
    			length ? fn( elems[ 0 ], key ) : emptyGet;
    }
    

    如上图,由于access函数用途并不局限于我们的.attr(),作为像笔者一样的jQuery初学者,源代码中有许多代码语句我们不能很好的理解(比如:if(bulk)部分).由于暂时接触到的jQuery内容较少较浅,我们如果一味深究,可能既搞不清楚原理,还浪费时间.所以,我们可以用一种简化的思想来分析问题: 只关注代码中跟我们当前问题有关的部分,忽略无关的,用不到的部分.

    具体做法:我们将.attr()的四种用法的实际传参情况带入jQuery.access函数的定义中,删除我们进不去的if语句代码块,只保留会用到的代码语句.


    调用形式:$("xxx").attr(name)

    attr定义:

    attr: function( name, value=undefined ) {
        return jQuery.access( this, jQuery.attr, name, value=undefined, arguments.length > 1 );
    }
    

    access调用简化:

    var access = function( this, jQuery.attr, name, value=undefined, chainable=false, emptyGet=undefined, raw=undefined ) {
    	var i = 0,
    		length = this.length, //jQuery对象的length属性(jQuery对象总是有length属性,它是类数组对象)
    		bulk = false;
    
    	return jQuery.attr( this[0], name );
    	};   
    

    同样,我们找到jQuery.attr()静态方法的源代码定义,用同样的简化方法分析,得到:

    jQuery.attr()完整源码:

    attr: function( elem, name, value ) {  // elem:DOM对象  name:属性名/键名 value:属性值
    	var ret, hooks,
    		nType = elem.nodeType;  // 节点类型
    
    	// 屏蔽属性节点,文本节点与注释节点
    	if ( nType === 3 || nType === 8 || nType === 2 ) {
    		return; 
    	}
    
    	// 当属性不支持getAttribute方法时,回调jQuery.prop()方法--从操作attribute变成了操作property
    	if ( typeof elem.getAttribute === "undefined" ) {
    		return jQuery.prop( elem, name, value );
    	}
    
    	
    //下面的都是DOM元素elem支持getAttribute的情况
    
    	// 所有标签特性(attributes)都是小写(处理兼容:有的浏览器对同一属性的名称可能大小写不停)
    	// 如果某一个是已定义的,抓取必要的钩子
    
    	if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {  // 非元素节点或者是XML文本中的元素
    		name = name.toLowerCase();
    		hooks = jQuery.attrHooks[ name ] ||  
    			( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook ); 
    	}
    
    	if ( value !== undefined ) {//如果value在传参时未被忽略
    		if ( value === null ) {
    			jQuery.removeAttr( elem, name );//传入第三个参数为null时,调用jQuery.removeAttr移除对应属性
    			return;
    		}
    
    		if ( hooks && "set" in hooks && 
    			( ret = hooks.set( elem, value, name ) ) !== undefined ) {
    			return ret;
    		}
    
    		elem.setAttribute( name, value + "" );
    		return value;
    	}
    
    	if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
    		return ret;
    	}
    
    	ret = jQuery.find.attr( elem, name );
    
    	// 不存在的属性会返回null,我们将之统一为undefined
    	return ret == null ? undefined : ret;
    }
    

    jQuery.attr()简化:

    attr: function( elem, name, value=undefined ) {  // elem:DOM对象  name:属性名/键名 value:属性值
    	var ret, hooks,
    		nType = 1;
    
    	ret = jQuery.find.attr( elem, name );
    
    	return ret;
    }   
    

    其中,唯一不确定的是jQuery.find.attr,然而我们继续找下去则是有关Sizzle选择器引擎的问题,这对于我们初学者来说过于复杂.因此,我们再简化一下,带入实际情景,检测这一函数的输出:

    var $p = $('#jQueryTest')[0];
    
    console.log(jQuery.find.attr($p,'id')); //jQueryTest   
    

    因此,大概知道该函数该种传参情况下的作用是返回指定DOM元素的指定属性的值.
    1.由jQuery.access简化代码中的return jQuery.attr( this[0], name );可知,只传入一个name参数的情况下,确实只会返回jQuery对象中的索引为'0'的DOM对象的指定属性的属性值.
    2.由jQuery.att()完整代码中
    if ( typeof elem.getAttribute === "undefined" ) {
    return jQuery.prop( elem, name, value );
    }

    可知:如果不支持get/setAttibute,那么原来的针对特性(attibute)的操作就会变成DOM元素属性(property)的操作.


    调用形式:$("xxx").attr(name,value);

    attr定义:

    attr: function( name, value) {  //此时的this是一个类数组
            return jQuery.access( this, fn=jQuery.attr, name, value, chainable=true);
        }
    

    access调用简化:

    var access = function( this, jQuery.attr, name, value, chainable=true, emptyGet=undefined, raw=undefined ) {
    	var i = 0,
    		length = this.length, //jQuery对象的length属性,表示找到的匹配的DOM元素的个数
    		bulk = false;
    
    
    		chainable = true;
    
    		if ( !jQuery.isFunction( value ) ) { //当value值不为函数时,设置raw为true,这是为了下一步if(jQuery.attr)中的raw判断做铺垫
    			raw = true; 
    		}
    
    		
    		if ( jQuery.attr ) { //jQuery.attr,为true
    
    			for ( ; i < length; i++ ) {  //用for循环是因为此时的this是一个包含多个DOM元素的jQuery对象
    				jQuery.attr(
    					this[ i ],
    					name,
    					raw ? value : value.call( elems[ i ], i, jQuery.attr( this[ i ], name ) )                       
    				);//raw为true,也就是value不为函数时,用value作第三参数
    			}	  
    		}
    	}
    
    	return this; //返回jQuery对象本身
    
    };
    

    而,我们用简化的方法分析此种情况下的jQuery.attr(this,name,value):

    attr: function( this[i], name, value ) {
    	var ret, hooks,
    		nType = this[i].nodeType;
    
    	if ( value !== undefined ) {  //判断为true,进入if语句
    		if ( value === null ) {
    			jQuery.removeAttr( this[i], name );//如果value为null,删除该jQuery对象的所有匹配元素的指定属性
    			return;
    		}
    
    		this[i].setAttribute( name, value + "" );//设置当前DOM元素的指定属性的属性值
    		return value;
    	}
    
    	ret = jQuery.find.attr( this[i], name ); //删除了属性,返回null;否则,返回指定属性的属性值
    
    	return ret == null ? undefined : ret; //如果删除了指定属性,返回undefined;如果修改了属性,返回指定属性值
    }
    

    调用形式:$("xxx").attr(attrObject);

    attr定义:

    attr: function( name=attrObject ) {
            return jQuery.access( this, jQuery.attr, name=attrObject, value=undefined, false);
        }
    

    access调用简化:

    var access = function( this, fn, name, value=undefined, chainable=false, emptyGet=undefined, raw=undefined ) {
    	var i = 0,
    		length = this.length, //元素的length属性
    		bulk = false;
    
    	// 设置多个value值
    	if ( jQuery.type( name ) === "object" ) { //如果传入的name形参为对象类型
    		chainable = true;
    		for ( i in name ) { //对每一个对象中的属性名及属性值再次调用本身(递归)
    			access( this, fn, i, name[ i ], true, emptyGet, raw );
    		}
    
    	}
    	return elems;  //返回jQuery对象本身
    
    };   
    

    可见,对于一个由"属性-属性值"键值对构成的对象,会对其中的每一个属性都调用access设置一次.由于代码中使用的for-in循环,所以enumerable为false的键值对是无效的.


    调用形式:$("xxx").attr(name,attrFn);

    attr定义:

    attr: function( name, value=attrFn ) {
            return jQuery.access( this, jQuery.attr, name, value=attrFn, chainable=true );
        }
    

    access调用简化:

    var access = function( this, jQuery.attr, name, value=attrFn, chainable=true, emptyGet=undefined, raw=undefined ) {
    	var i = 0,
    		length = this.length, //jQuery对象的length属性
    		bulk = false;
    
    		chainable = true;
    
    		if ( jQuery.attr ) {  //true,进入if语句
    			for ( ; i < length; i++ ) {
    				jQuery.attr(
    					this[ i ],
    					name,
    					attrFn.call( this[ i ], i, jQuery.attr( this[ i ], name ) )  // 调用attrFn,其返回值作为第三个参数                    				         
    				);
    			}
    		}
    
    	return elems; // 返回jQuery对象本身
    };
    

    attrFn.call( this[ i ], i, jQuery.attr( this[ i ], name ) )可知,attrFn的参数限制就是源自这一行代码:(this[i]是调用attrFn的元素,后面两个是参数,一个是jQuery对象中的索引值,一个是当前元素的指定属性name的值的查询返回)

    [特别注意:attrFn的两个参数虽然有规定,但是不需要我们真的传参,而是函数体内部使用索引值或者当前属性值的一个接口]

  • 相关阅读:
    Unity Shader _Time 的单位
    egg-sequelize 实现 增删改查
    Eggjs 联表查询
    Eggjs 菜单权限管理
    Eggjs 角色管理 -- 对角色树进行 增删改查
    Egg.js 实现一维的对象数组转化为树形数组
    Egg.js 中 Session 的设置和获取
    Egg.js 中 Cookie 的设置和获取
    Egg 安全机制 CSRF 的防范
    Egg middleware 中间件
  • 原文地址:https://www.cnblogs.com/peterzhangsnail/p/10030013.html
Copyright © 2020-2023  润新知