jQuery属性操作之.attr()
目录
转载请注明出处
@
.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 ) { //当传入key值为null时的处理情况(这段代码,我们在分析.attr()时不会用到) // bulk operations run against the entire set if ( raw ) { fn.call( elems, value ); fn = null; // ...except when executing function values } 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()静态方法的源代码定义,用同样的简化方法分析,得到:
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元素的指定属性的值.
由jquery.access简化代码中的return jquery.attr( this[0], name );
可知,只传入一个name参数的情况下,确实只会返回jquery对象中的索引为'0'的dom对象的指定属性的属性值.
调用形式:$("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的两个参数虽然有规定,但是不需要我们真的传参,而是函数体内部使用索引值或者当前属性值的一个接口]