是否已经开发了使用setAttribute代替点(.)属性表示法的最佳实践?

例如:

myObj.setAttribute("className", "nameOfClass");
myObj.setAttribute("id", "someID");

or

myObj.className = "nameOfClass";
myObj.id = "someID";

如果您希望在JavaScript中进行编程访问,您应该始终使用直接的.attribute形式(但请参阅下面的quirksmode链接)。它应该正确地处理不同类型的属性(想想“onload”)。

使用getAttribute/setAttribute当你希望处理DOM,因为它是(例如,文字文本)。不同的浏览器会混淆这两者。参见怪癖模式:属性(在)兼容性。


来自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

这看起来像是使用setAttribute更好的一种情况:

高效的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);
}

我发现需要使用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中有三种访问DOM元素属性的方法。这三种方法都可以在现代浏览器中可靠地工作,只要您了解如何使用它们。

1. element.attributes

元素有一个属性属性,它返回Attr对象的活动NamedNodeMap。此集合的索引可能因浏览器而异。所以,顺序是不能保证的。NamedNodeMap有添加和删除属性的方法(分别是getNamedItem和setNamedItem)。

注意,尽管XML显式区分大小写,但DOM规范要求规范化字符串名称,因此传递给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>

2. element.getAttribute & element.setAttribute

这些方法直接存在于Element上,不需要访问属性及其方法,但执行相同的功能。

再次注意,字符串名称是不区分大小写的。

使用示例:

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>

3.DOM对象上的属性,例如element.id

使用DOM对象上的方便属性可以访问许多属性。给定对象上存在哪些属性取决于对象的DOM节点类型,而与HTML中指定的属性无关。可用的属性定义在DOM对象原型链中的某个地方。因此,所定义的特定属性将取决于您正在访问的Element的类型。

例如,className和id定义在Element上,存在于所有DOM节点上,这些节点是元素,但不包括文本或注释节点。价值的定义更为狭义。它只在HTMLInputElement和它的后代上可用。

注意,JavaScript属性是区分大小写的。尽管大多数属性将使用小写字母,但也有一些是驼峰式的。所以一定要检查说明书。

这个“图表”捕获了这些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规范如何定义属性,以及现代的常青浏览器如何处理属性。当然,有些老的浏览器(IE、Netscape等)没有遵守这个规范,甚至比这个规范更早。如果你需要支持旧的(破损的)浏览器,你需要的信息比这里提供的更多。


“在JavaScript中什么时候使用setAttribute vs .attribute= ?”

一般的规则是使用.attribute并检查它是否在浏览器上工作。

..如果它可以在浏览器上运行,那么就可以开始了。

..如果没有,使用. setattribute (attribute, value)来代替该属性的.attribute。

冲洗-重复所有属性。

如果你很懒,你可以简单地使用. setattribute。这在大多数浏览器上都可以正常工作。(尽管支持.attribute的浏览器可以比. setattribute (attribute, value)更好地优化它。)


在元素上设置属性(例如class)的方法: 1. 埃尔。className = string 2. el.setAttribute(‘类’,字符串) 3.el.attributes.setNamedItem(对象) 4. el.setAttributeNode(节点)

我做了一个简单的基准测试(这里)

似乎setAttributeNode比使用setAttribute快3倍。

所以如果性能是一个问题-使用“setAttributeNode”


这些答案并没有真正解决属性和属性之间的巨大混淆。此外,根据Javascript原型,有时可以使用元素的属性访问属性,有时不能。

首先,您必须记住HTMLElement是一个Javascript对象。像所有对象一样,它们也有属性。当然,您可以在HTMLElement中创建几乎任何名称的属性,但它不需要与DOM(页面上的内容)做任何事情。点符号(.)用于属性。现在,有一些特殊的属性被映射到属性,在编写时,只有4个属性是有保证的(稍后会详细介绍)。

All HTMLElements include a property called attributes. HTMLElement.attributes is a live NamedNodeMap Object that relates to the elements in the DOM. "Live" means that when the node changes in the DOM, they change on the JavaScript side, and vice versa. DOM attributes, in this case, are the nodes in question. A Node has a .nodeValue property that you can change. NamedNodeMap objects have a function called setNamedItem where you can change the entire node. You can also directly access the node by the key. For example, you can say .attributes["dir"] which is the same as .attributes.getNamedItem('dir'); (Side note, NamedNodeMap is case-insensitive, so you can also pass '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的扩展

HTMLElement has those 4 special properties. Some elements are extended classes of HTMLElement have even more mapped properties. For example, HTMLAnchorElement has HTMLAnchorElement.href, HTMLAnchorElement.rel, and HTMLAnchorElement.target. But, beware, if you set those properties on elements that do not have those special properties (like on a HTMLTableElement) then the attributes aren't changed and they are just, normal custom properties. To better understand, here's an example of its inheritance:

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。基本上,依次为:

自定义属性,因为它们不影响DOM,也不是属性。 浏览器提供的特殊映射(dir, id, className)。 如果属性已经存在,则element.attributes.ATTRIBUTENAME.nodeValue = setAttribute (); 如果属性已经存在,则element.attributes.getNamedItem(ATTRIBUTENAME)。nodeValue = newValue element.attributes.ATTRIBUTENAME = newNode element.attributes.setNamedItem(ATTRIBUTENAME) = newNode

结论(TL;博士)

使用来自HTMLElement: element的特殊属性映射。dir,元素。id元素。className或element.lang。 如果您100%确定该元素是具有特殊属性的扩展HTMLElement,则使用该特殊映射。你可以用if (element instanceof htmllanchorelement)来检查。 如果您100%确定属性已经存在,则使用element.attributes.ATTRIBUTENAME.nodeValue = newValue。 如果不是,使用setAttribute()。


谷歌API脚本对此进行了有趣的观察:

他们是这样做的:

var scriptElement = document.createElement("script");
scriptElement = setAttribute("src", "https://some.com");
scriptElement = setAttribute("nonce", "https://some.com");
scriptElement.async = "true";

注意,他们如何为"src"和"nonce"使用setAttribute,但是。async =…对于“async”属性。

我不是100%确定,但可能是因为“async”只在支持直接。attr =赋值的浏览器上被支持。因此,尝试setAttribute("async")是没有意义的,因为如果浏览器不理解.async=…它不会理解“async”属性。

希望这是我正在进行的“非最小化GAPI”研究项目的有益见解。如果我说错了,请指正。


这是很好的讨论。我曾有过这样的时刻,我希望,或者让我说希望(我可以补充说,是成功的)重新发明轮子,不管它是正方形的。 上面的任何方法都是很好的讨论,所以任何来这里寻找Element属性和属性之间的区别的人。这是我最值钱的一分钱,我的确是费了好大劲才发现的。我会保持简单,所以没有特别的技术术语。

假设我们有一个变量a。我们所习惯的如下。

下面会抛出一个错误,因为它简单地写了它是一种只能有一个属性的对象,即单数左手边对象=单数右手边对象。其他的东西都被忽略,扔进垃圾桶。 let A = 'f'; A.b = 2; console.log (A.b);

谁决定它必须是单数=单数。那些制定JavaScript和html标准的人,这就是引擎工作的方式。

让我们换个例子。

let A = {}; A.b = 2; console.log (A.b);

这一次它工作.....因为我们已经明确地告诉它了,谁决定我们可以在这个例子中告诉它,而不是在以前的例子中。还是那些制定JavaScript和html标准的人。

我希望我们在这个问题上,让它进一步复杂化

let A = {}; A.attribute = {}; A.attribute.b = 5; console.log (A.attribute.b);//将工作 console.log (A.b);//将不起作用

我们所做的是第一层的树和非奇异对象的子层。除非你知道什么是哪里,并调用它,否则它将工作。

这就是HTMLDOM在为每个HTML元素创建解析和绘制DOm树时所发生的事情。每个都有不同级别的属性。有些是预定义的,有些不是。这就是ID和VALUE位发挥作用的地方。 在场景后面,它们在1级属性和sun级属性(属性)之间以1:1的比例映射。因此,改变一个就会改变另一个。这就是对象getter和setter方案的作用。

let A = { attribute :{ id:'', value:'' }, getAttributes: function (n) { return this.attribute[n]; }, setAttributes: function (n,nn){ this.attribute[n] = nn; if(this[n]) this[n] = nn; }, id:'', value:'' }; A.id = 5; console.log(A.id); console.log(A.getAttributes('id')); A.setAttributes('id',7) console.log(A.id); console.log(A.getAttributes('id')); A.setAttributes('ids',7) console.log(A.ids); console.log(A.getAttributes('ids')); A.idsss=7; console.log(A.idsss); console.log(A.getAttributes('idsss'));

如上所示,ELEMENTS有另一组所谓的属性列表属性,它有自己的主要属性。在两者之间有一些预定义的属性,并以1:1的比例映射,例如ID对每个人都是公共的,但value不是,src也不是。当解析器到达这一点时,它只是简单地调出字典,以确定何时出现这样那样的东西。

所有元素都有属性和属性,它们之间的一些项是公共的。在一个国家常见的东西在另一个国家并不常见。

在过去的HTML3时代,我们首先使用html,然后使用JS。现在的日子,它的其他方式,所以已经使用内联onclick成为如此令人憎恶。在HTML5中,有许多属性列表可以作为集合访问,例如类,样式。在过去,颜色是一个属性,现在被移动到css处理不再有效的属性。

元素。attributes是元素属性中的子属性列表。

除非你能改变Element属性的getter和setter,这几乎是不可能的,因为它会破坏所有的功能,通常是不能立即写出来的,只是因为我们定义了一个A.item并不一定意味着Js引擎也会运行另一行函数将它添加到Element.attributes.item中。

我希望这能进一步澄清什么是什么。 为了这个目的,我尝试了element。prototype。setattribute和自定义函数,它只是打破了所有的东西,因为它覆盖了本地的一堆函数,设置属性函数在幕后发挥作用。


增加2个与.textContent和.innerHTML相关的点

<div id="mydiv"></div>


var elem = document.getElementById("mydiv");

elem.textContent = "hello"; // OK - Content has been updated
elem.setAttribute("textContent", "hello"); // NOT OK - You are trying to set
                                           // the attribute than it's content

elem.innerHTML = "world";   // OK - Content has been updated
elem.setAttribute("innerHTML", "world"); // NOT OK - You are trying to set
                                         // the attribute than it's content

两者之间的一个区别是setAttribute,当用于设置<input/>的值时,将使该值成为它所在表单上调用.reset()时的默认值,但.value =不会这样做。

https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset

注意,如果调用setAttribute()来设置特定属性的值,则后续调用reset()不会将该属性重置为其默认值,而是将该属性保持setAttribute()调用设置的值。


If the element you are referring to does not already include a Javascript object property for a given attribute (as others have described), then setting that property will not propagate the change back to the DOM, it just adds the named property to the Javascript object, and the DOM ignores it. For example, getting the element mySpan by id and then doing mySpan.class = 'warning' will do nothing, whether or not the span element in question already has a class attribute defined, because mySpan.class is not defined in the Javascript object for a span element. You have to use mySpan.setAttribute('class', 'warning').

然而,第二个细微差别是使用mySpan设置Javascript对象的innerHTML属性。setAttribute("innerHTML", someHTML)不会更新元素的内容。我不知道Javascript是如何捕获mySpan的。innerHTML = something,并调用HTML解析器,但在底层有一些神奇的东西。