深入学习jquery源码之attr()与removeAttr()
attr(name|properties|key,value|fn)
概述
设置或返回被选元素的属性值。
参数
name String
属性名称
properties Map
作为属性的“名/值对”对象
key,value String,Object
属性名称,属性值
key,function(index, attr) String,Function
1:属性名称。
2:返回属性值的函数,第一个参数为当前元素的索引值,第二个参数为原先的属性值。
返回文档中所有图像的src属性值。
$("img").attr("src");
为所有图像设置src和alt属性。
$("img").attr({ src: "test.jpg", alt: "Test Image" });
为所有图像设置src属性。
$("img").attr("src","test.jpg");
把src属性的值设置为title属性的值。
$("img").attr("title", function() { return this.src });
removeAttr(name)
概述
从每一个匹配的元素中删除一个属性
1.6以下版本在IE6使用JQuery的removeAttr方法删除disabled是无效的。解决的方法就是使用$("XX").prop("disabled",false);
1.7版本在IE6下已支持删除disabled。
参数
name String
要删除的属性名
将文档中图像的src属性删除
<img src="test.jpg"/>
$("img").removeAttr("src");
[ <img /> ]
jquery源码
// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
var access = jQuery.access = function (elems, fn, key, value, chainable, emptyGet, raw) {
var i = 0,
length = elems.length,
bulk = key == null;
// Sets many values
if (jQuery.type(key) === "object") {
chainable = true;
for (i in key) {
jQuery.access(elems, fn, i, key[i], true, emptyGet, raw);
}
// Sets one value
} else if (value !== undefined) {
chainable = true;
if (!jQuery.isFunction(value)) {
raw = true;
}
if (bulk) {
// 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) {
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;
};
var nodeHook, boolHook,
attrHandle = jQuery.expr.attrHandle,
ruseDefault = /^(?:checked|selected)$/i,
getSetAttribute = support.getSetAttribute,
getSetInput = support.input;
jQuery.fn.extend({
attr: function (name, value) {
return access(this, jQuery.attr, name, value, arguments.length > 1);
},
removeAttr: function (name) {
return this.each(function () {
jQuery.removeAttr(this, name);
});
}
});
jQuery.extend({
attr: function (elem, name, value) {
var hooks, ret,
nType = elem.nodeType;
// don't get/set attributes on text, comment and attribute nodes
if (!elem || nType === 3 || nType === 8 || nType === 2) {
return;
}
// Fallback to prop when attributes are not supported
if (typeof elem.getAttribute === strundefined) {
return jQuery.prop(elem, name, value);
}
// All attributes are lowercase
// Grab necessary hook if one is defined
if (nType !== 1 || !jQuery.isXMLDoc(elem)) {
name = name.toLowerCase();
hooks = jQuery.attrHooks[name] ||
(jQuery.expr.match.bool.test(name) ? boolHook : nodeHook);
}
if (value !== undefined) {
if (value === null) {
jQuery.removeAttr(elem, name);
} else if (hooks && "set" in hooks && (ret = hooks.set(elem, value, name)) !== undefined) {
return ret;
} else {
elem.setAttribute(name, value + "");
return value;
}
} else if (hooks && "get" in hooks && (ret = hooks.get(elem, name)) !== null) {
return ret;
} else {
ret = jQuery.find.attr(elem, name);
// Non-existent attributes return null, we normalize to undefined
return ret == null ?
undefined :
ret;
}
},
removeAttr: function (elem, value) {
var name, propName,
i = 0,
attrNames = value && value.match(rnotwhite);
if (attrNames && elem.nodeType === 1) {
while ((name = attrNames[i++])) {
propName = jQuery.propFix[name] || name;
// Boolean attributes get special treatment (#10870)
if (jQuery.expr.match.bool.test(name)) {
// Set corresponding property to false
if (getSetInput && getSetAttribute || !ruseDefault.test(name)) {
elem[propName] = false;
// Support: IE<9
// Also clear defaultChecked/defaultSelected (if appropriate)
} else {
elem[jQuery.camelCase("default-" + name)] =
elem[propName] = false;
}
// See #9699 for explanation of this approach (setting first, then removal)
} else {
jQuery.attr(elem, name, "");
}
elem.removeAttribute(getSetAttribute ? name : propName);
}
}
},
attrHooks: {
type: {
set: function (elem, value) {
if (!support.radioValue && value === "radio" && jQuery.nodeName(elem, "input")) {
// Setting the type on a radio button after the value resets the value in IE6-9
// Reset value to default in case type is set after value during creation
var val = elem.value;
elem.setAttribute("type", value);
if (val) {
elem.value = val;
}
return value;
}
}
}
}
});
// Hook for boolean attributes
boolHook = {
set: function (elem, value, name) {
if (value === false) {
// Remove boolean attributes when set to false
jQuery.removeAttr(elem, name);
} else if (getSetInput && getSetAttribute || !ruseDefault.test(name)) {
// IE<8 needs the *property* name
elem.setAttribute(!getSetAttribute && jQuery.propFix[name] || name, name);
// Use defaultChecked and defaultSelected for oldIE
} else {
elem[jQuery.camelCase("default-" + name)] = elem[name] = true;
}
return name;
}
};
// Retrieve booleans specially
jQuery.each(jQuery.expr.match.bool.source.match(/\w+/g), function (i, name) {
var getter = attrHandle[name] || jQuery.find.attr;
attrHandle[name] = getSetInput && getSetAttribute || !ruseDefault.test(name) ?
function (elem, name, isXML) {
var ret, handle;
if (!isXML) {
// Avoid an infinite loop by temporarily removing this function from the getter
handle = attrHandle[name];
attrHandle[name] = ret;
ret = getter(elem, name, isXML) != null ?
name.toLowerCase() :
null;
attrHandle[name] = handle;
}
return ret;
} :
function (elem, name, isXML) {
if (!isXML) {
return elem[jQuery.camelCase("default-" + name)] ?
name.toLowerCase() :
null;
}
};
});
// fix oldIE attroperties
if (!getSetInput || !getSetAttribute) {
jQuery.attrHooks.value = {
set: function (elem, value, name) {
if (jQuery.nodeName(elem, "input")) {
// Does not return so that setAttribute is also used
elem.defaultValue = value;
} else {
// Use nodeHook if defined (#1954); otherwise setAttribute is fine
return nodeHook && nodeHook.set(elem, value, name);
}
}
};
}
// IE6/7 do not support getting/setting some attributes with get/setAttribute
if (!getSetAttribute) {
// Use this for any attribute in IE6/7
// This fixes almost every IE6/7 issue
nodeHook = {
set: function (elem, value, name) {
// Set the existing or create a new attribute node
var ret = elem.getAttributeNode(name);
if (!ret) {
elem.setAttributeNode(
(ret = elem.ownerDocument.createAttribute(name))
);
}
ret.value = value += "";
// Break association with cloned elements by also using setAttribute (#9646)
if (name === "value" || value === elem.getAttribute(name)) {
return value;
}
}
};
// Some attributes are constructed with empty-string values when not defined
attrHandle.id = attrHandle.name = attrHandle.coords =
function (elem, name, isXML) {
var ret;
if (!isXML) {
return (ret = elem.getAttributeNode(name)) && ret.value !== "" ?
ret.value :
null;
}
};
// Fixing value retrieval on a button requires this module
jQuery.valHooks.button = {
get: function (elem, name) {
var ret = elem.getAttributeNode(name);
if (ret && ret.specified) {
return ret.value;
}
},
set: nodeHook.set
};
// Set contenteditable to false on removals(#10429)
// Setting to empty string throws an error as an invalid value
jQuery.attrHooks.contenteditable = {
set: function (elem, value, name) {
nodeHook.set(elem, value === "" ? false : value, name);
}
};
// Set width and height to auto instead of 0 on empty string( Bug #8150 )
// This is for removals
jQuery.each(["width", "height"], function (i, name) {
jQuery.attrHooks[name] = {
set: function (elem, value) {
if (value === "") {
elem.setAttribute(name, "auto");
return value;
}
}
};
});
}
if (!support.style) {
jQuery.attrHooks.style = {
get: function (elem) {
// Return undefined in the case of empty string
// Note: IE uppercases css property names, but if we were to .toLowerCase()
// .cssText, that would destroy case senstitivity in URL's, like in "background"
return elem.style.cssText || undefined;
},
set: function (elem, value) {
return (elem.style.cssText = value + "");
}
};
}