jQuery源码阅读8-2:属性操作val(),removeAttr()

属性操作是比较独立的一块,
这次说下prop相关的, 和属性必须用的access 下次说更麻烦一点的attr,val 还有css相关的

以prop的一次操作为例, 调用顺序是: fn.prop -> access -> jQuery.prop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
core_rspace = /\s+/,//匹配一些列空格
// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
getSetAttribute: div.className !== "t",
removeAttr: function( elem, value ) {
var propName, attrNames, name, isBool,
i = 0;
//nodeType === 1代表elem是普通dom元素
if ( value && elem.nodeType === 1 ) {
//按空格切分成数组
attrNames = value.split( core_rspace );
//处理elem一次传入多个值
for ( ; i < attrNames.length; i++ ) {
name = attrNames[ i ];
if ( name ) {
//修复名称
propName = jQuery.propFix[ name ] || name;
//是否在布尔参数的列表里
isBool = rboolean.test( name );
// See #9699 for explanation of this approach (setting first, then removal)
// Do not do this for boolean attributes (see #10870)
//不是布尔的, 写入""
if ( !isBool ) {
jQuery.attr( elem, name, "" );
}
//因为兼容问题,先写入空, 再removeAttribute, 这个getSetAttribute检测div.className是否等于t
elem.removeAttribute( getSetAttribute ? name : propName );
// Set corresponding property to false for boolean attributes
//布尔型的写入false
if ( isBool && propName in elem ) {
elem[ propName ] = false;
}
}
}
}
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
rreturn = /\r/g,//匹配回车
val: function( value ) {
var hooks, ret, isFunction,
elem = this[0];//目标元素
//无参数, 读取
if ( !arguments.length ) {
if ( elem ) {
//这的钩子针对option和select
hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
//产生钩子了,就调用钩子
if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
return ret;
}
ret = elem.value;
return typeof ret === "string" ?
//结果是string, 把回车去掉
ret.replace(rreturn, "") :
//数字直接返回, undefined和null返回""
ret == null ? "" : ret;
}
return;
}
//value接收的是否是函数
isFunction = jQuery.isFunction( value );
//有参数,写入模式
return this.each(function( i ) {
var val,
self = jQuery(this);//这个this是当前遍历的dom元素
//nodeType必须是普通dom
if ( this.nodeType !== 1 ) {
return;
}
if ( isFunction ) {
//传入函数.call( 当前dom, idx , 当前dom的.val()值 )
val = value.call( this, i, self.val() );
} else {
//val先等于value待处理
val = value;
}
//undefined和null处理成"", 数组处理为string ,
if ( val == null ) {
val = "";
} else if ( typeof val === "number" ) {
val += "";
} else if ( jQuery.isArray( val ) ) {
//利用map转成字串数组
val = jQuery.map(val, function ( value ) {
return value == null ? "" : value + "";
});
}
//特殊处理select的set的钩子
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
//钩子里有set则使用钩子写入
if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
this.value = val;
}
});
}
});
jQuery.extend({
valHooks: {
option: {
get: function( elem ) {
//兼容读取elem.attributes.value
var val = elem.attributes.value;
return !val || val.specified ? elem.value : elem.text;
}
},
select: {
get: function( elem ) {
var value, option,
options = elem.options,//数组
index = elem.selectedIndex,//选中序号
one = elem.type === "select-one" || index < 0,//是否是单选
values = one ? null : [],//缓存结果
max = one ? index + 1 : options.length,
i = index < 0 ?
max :
one ? index : 0;
//遍历所有options
for ( ; i < max; i++ ) {
option = options[ i ];
//一堆兼容处理
if ( ( option.selected || i === index ) &&
// Don't return options that are disabled or in a disabled optgroup
( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
// Get the specific value for the option
value = jQuery( option ).val();
//单选就一个
if ( one ) {
return value;
}
//多选加入数组
values.push( value );
}
}
return values;
},
set: function( elem, value ) {
//整理成参数数组
var values = jQuery.makeArray( value );
//找子元素,
jQuery(elem).find("option").each(function() {
//出现在values数组的就选上
this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
});
//如果values没值,selectedIndex做处理
if ( !values.length ) {
elem.selectedIndex = -1;
}
return values;
}
}
},