有没有开发使用setAttribute
而不是dot(.
)属性符号的最佳实践?
Ef。:
myObj.setAttribute("className", "nameOfClass");
myObj.setAttribute("id", "someID");
要么
myObj.className = "nameOfClass";
myObj.id = "someID";
如果您想在JavaScript中进行编程访问,则应始终使用直接.attribute
表单(但请参阅下面的quirksmode链接)。它应该正确处理不同类型的属性(想想“onload”)。
当您希望按原样处理DOM时使用getAttribute
/ setAttribute
(例如仅限文字文本)。不同的浏览器混淆了两者。见Quirks modes: attribute (in)compatibility。
从Javascript: The Definitive Guide,它澄清了事情。它指出HTML文档的HTMLElement对象定义了与所有标准HTML属性相对应的JS属性。
所以你只需要使用setAttribute
作为非标准属性。
例:
node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
之前的答案都没有完整,大多数都包含错误的信息。
在JavaScript中有三种方法可以访问DOM Element的属性。只要您了解如何使用它们,这三种方法都可以在现代浏览器中可靠地工作。
element.attributes
元素有一个属性attributes,返回NamedNodeMap对象的实时Attr。浏览器中此集合的索引可能不同。因此,订单无法保证。 NamedNodeMap
有添加和删除属性的方法(分别为getNamedItem
和setNamedItem
)。
请注意,尽管XML明确区分大小写,但DOM规范要求string names to be normalized,因此传递给getNamedItem
的名称实际上不区分大小写。
var div = document.getElementsByTagName('div')[0];
//you can look up specific attributes
var classAttr = div.attributes.getNamedItem('CLASS');
document.write('attributes.getNamedItem() Name: ' + classAttr.name + ' Value: ' + classAttr.value + '<br>');
//you can enumerate all defined attributes
for(var i = 0; i < div.attributes.length; i++) {
var attr = div.attributes[i];
document.write('attributes[] Name: ' + attr.name + ' Value: ' + attr.value + '<br>');
}
//create custom attribute
var customAttr = document.createAttribute('customTest');
customAttr.value = '567';
div.attributes.setNamedItem(customAttr);
//retreive custom attribute
customAttr = div.attributes.getNamedItem('customTest');
document.write('attributes.getNamedItem() Name: ' + customAttr.name + ' Value: ' + customAttr.value + '<br>');
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
element.getAttribute
&element.setAttribute
这些方法直接存在于Element
上,无需访问attributes
及其方法,但执行相同的功能。
再次注意,字符串名称不区分大小写。
var div = document.getElementsByTagName('div')[0];
//get specific attributes
document.write('Name: class Value: ' + div.getAttribute('class') + '<br>');
document.write('Name: ID Value: ' + div.getAttribute('ID') + '<br>');
document.write('Name: DATA-TEST Value: ' + div.getAttribute('DATA-TEST') + '<br>');
document.write('Name: nonStandard Value: ' + div.getAttribute('nonStandard') + '<br>');
//create custom attribute
div.setAttribute('customTest', '567');
//retreive custom attribute
document.write('Name: customTest Value: ' + div.getAttribute('customTest') + '<br>');
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
element.id
可以使用DOM对象上的方便属性访问许多属性。存在哪些属性取决于DOM节点的类型,而不是HTML中定义的属性。属性在DOM对象的原型链中的某处定义。定义的特定属性取决于您正在访问的Element的类型。例如,className
和id
在Element
上定义,并且存在于作为元素的所有DOM节点上(即,不是文本或注释节点)。但value
更狭隘。它在HTMLInputElement
上定义,可能不存在于其他元素上。
请注意,JavaScript属性区分大小写。虽然大多数属性都使用小写,但有些属性是camelCase。因此,请务必检查规格。
这个“图表”捕获了这些DOM对象的原型链的一部分。它甚至还没有完成,但它捕获了整体结构。
____________Node___________
| | |
Element Text Comment
| |
HTMLElement SVGElement
| |
HTMLInputElement HTMLSpanElement
var div = document.getElementsByTagName('div')[0];
//get specific attributes
document.write('Name: class Value: ' + div.className + '<br>');
document.write('Name: id Value: ' + div.id + '<br>');
document.write('Name: ID Value: ' + div.ID + '<br>'); //undefined
document.write('Name: data-test Value: ' + div.dataset.test + '<br>'); //.dataset is a special case
document.write('Name: nonStandard Value: ' + div.nonStandard + '<br>'); //undefined
<div class="class1" id="main" data-test="stuff" nonStandard="1234"></div>
警告:这是对HTML规范定义和现代浏览器如何处理属性的解释。我没有尝试处理古老的,破碎的浏览器的局限性。如果您需要支持旧版浏览器,除了这些信息之外,您还需要了解这些浏览器中的内容。
我发现需要setAttribute
的一个案例是在更改ARIA属性时,因为没有相应的属性。例如
x.setAttribute('aria-label', 'Test');
x.getAttribute('aria-label');
没有x.arialabel
或类似的东西,所以你必须使用setAttribute。
编辑:x [“aria-label”]不起作用。你确实需要setAttribute。
x.getAttribute('aria-label')
null
x["aria-label"] = "Test"
"Test"
x.getAttribute('aria-label')
null
x.setAttribute('aria-label', 'Test2')
undefined
x["aria-label"]
"Test"
x.getAttribute('aria-label')
"Test2"
“何时在JavaScript中使用setAttribute vs .attribute =?”
一般规则是使用.attribute
并检查它是否在浏览器上有效。
..如果它适用于浏览器,你很高兴。
..如果没有,请使用.setAttribute(attribute, value)
而不是.attribute
作为该属性。
冲洗重复所有属性。
好吧,如果你很懒,你可以简单地使用.setAttribute
。这应该适用于大多数浏览器。 (虽然支持.attribute
的浏览器可以比.setAttribute(attribute, value)
更好地优化它。)
这些答案并没有真正解决属性和属性之间的巨大混淆。此外,根据Javascript原型,有时您可以使用元素的属性来访问属性,有时您不能。
首先,你必须记住HTMLElement
是一个Javascript对象。像所有对象一样,它们具有属性。当然,你可以在HTMLElement
中创建一个几乎任何你想要的属性,但它不需要对DOM做任何事情(页面上有什么)。点符号(.
)用于属性。现在,有一些特殊的属性被映射到属性,当时或写作只有4个有保证(稍后会有更多)。
所有HTMLElement
s都包括一个名为attributes
的财产。 HTMLElement.attributes
是一个活的NamedNodeMap
对象,它与DOM中的元素有关。 “实时”意味着当节点在DOM中发生变化时,它们会在JavaScript端发生变化,反之亦然。在这种情况下,DOM属性是有问题的节点。 Node
有一个.nodeValue
属性,你可以改变。 NamedNodeMap
对象有一个名为setNamedItem
的函数,您可以在其中更改整个节点。您也可以通过密钥直接访问节点。例如,你可以说.attributes["dir"]
与.attributes.getNamedItem('dir');
相同(旁注,NamedNodeMap
不区分大小写,所以你也可以通过'DIR'
);
在HTMLElement
中有一个类似的函数,你可以调用setAttribute
,如果它不存在则自动创建一个节点并设置nodeValue
。您还可以通过特殊属性(如HTMLElement
)直接作为dir
中的属性访问某些属性。这是一个粗略的映射:
HTMLElement {
attributes: {
setNamedItem: function(attr, newAttr) {
this[attr] = newAttr;
},
getNamedItem: function(attr) {
return this[attr];
},
myAttribute1: {
nodeName: 'myAttribute1',
nodeValue: 'myNodeValue1'
},
myAttribute2: {
nodeName: 'myAttribute2',
nodeValue: 'myNodeValue2'
},
}
setAttribute: function(attr, value) {
let item = this.attributes.getNamedItem(attr);
if (!item) {
item = document.createAttribute(attr);
this.attributes.setNamedItem(attr, item);
}
item.nodeValue = value;
},
getAttribute: function(attr) {
return this.attributes[attr] && this.attributes[attr].nodeValue;
},
dir: // Special map to attributes.dir.nodeValue || ''
id: // Special map to attributes.id.nodeValue || ''
className: // Special map to attributes.class.nodeValue || ''
lang: // Special map to attributes.lang.nodeValue || ''
}
所以你可以通过6种方式改变dir
属性:
// 1. Replace the node with setNamedItem
const newAttribute = document.createAttribute('dir');
newAttribute.nodeValue = 'rtl';
element.attributes.setNamedItem(newAttribute);
// 2. Replace the node by property name;
const newAttribute2 = document.createAttribute('dir');
newAttribute2.nodeValue = 'rtl';
element.attributes['dir'] = newAttribute2;
// OR
element.attributes.dir = newAttribute2;
// 3. Access node with getNamedItem and update nodeValue
// Attribute must already exist!!!
element.attributes.getNamedItem('dir').nodeValue = 'rtl';
// 4. Access node by property update nodeValue
// Attribute must already exist!!!
element.attributes['dir'].nodeValue = 'rtl';
// OR
element.attributes.dir.nodeValue = 'rtl';
// 5. use setAttribute()
element.setAttribute('dir', 'rtl');
// 6. use the UNIQUELY SPECIAL dir property
element["dir"] = 'rtl';
element.dir = 'rtl';
您可以使用方法#1-5更新所有属性,但只能使用方法#6更新dir
,id
,lang
和className
。
HTMLElement
有4个特殊属性。一些元素是HTMLElement
的扩展类具有更多的映射属性。例如,HTMLAnchorElement
有HTMLAnchorElement.href
,HTMLAnchorElement.rel
和HTMLAnchorElement.target
。但是,请注意,如果您在不具有这些特殊属性的元素上设置这些属性(例如在HTMLTableElement
上),那么属性不会更改,它们只是普通的自定义属性。为了更好地理解,这是一个继承的例子:
HTMLAnchorElement extends HTMLElement {
// inherits all of HTMLElement
href: // Special map to attributes.href.nodeValue || ''
target: // Special map to attributes.target.nodeValue || ''
rel: // Special map to attributes.ref.nodeValue || ''
}
现在大警告:像所有Javascript对象一样,您可以添加自定义属性。但是,这些不会改变DOM上的任何内容。你可以做:
const newElement = document.createElement('div');
// THIS WILL NOT CHANGE THE ATTRIBUTE
newElement.display = 'block';
但那是一样的
newElement.myCustomDisplayAttribute = 'block';
这意味着添加自定义属性不会链接到.attributes[attr].nodeValue
。
性能
我已经构建了一个jsperf测试用例来显示差异:https://jsperf.com/set-attribute-comparison。基本上,按顺序:
dir
,id
,className
)。element.attributes.ATTRIBUTENAME.nodeValue =
element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
element.attributes.ATTRIBUTENAME = newNode
element.attributes.setNamedItem(ATTRIBUTENAME) = newNode
结论(TL; DR)
HTMLElement
:element.dir
,element.id
,element.className
或element.lang
的特殊属性映射。HTMLElement
,请使用该特殊映射。 (你可以查看if (element instanceof HTMLAnchorElement)
)。element.attributes.ATTRIBUTENAME.nodeValue = newValue
。setAttribute()
。这看起来像使用setAttribute更好的一种情况:
Dev.Opera — Efficient JavaScript
var posElem = document.getElementById('animation');
var newStyle = 'background: ' + newBack + ';' +
'color: ' + newColor + ';' +
'border: ' + newBorder + ';';
if(typeof(posElem.style.cssText) != 'undefined') {
posElem.style.cssText = newStyle;
} else {
posElem.setAttribute('style', newStyle);
}
在元素上设置属性(例如类)的方法:1.el.className = string 2. el.setAttribute('class',string)3。el.attributes.setNamedItem(object)4。el.setAttributeNode(node)
我做了一个简单的基准测试(here)
似乎setAttributeNode比使用setAttribute快约3倍。
所以如果性能是一个问题 - 使用“setAttributeNode”