何时在 JavaScript 中使用 setAttribute 与 .attribute= ?

IT技术 javascript attributes setattribute
2021-02-05 04:11:26

是否已开发出围绕使用setAttribute而不是点 ( .) 属性符号的最佳实践

例如:

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

或者

myObj.className = "nameOfClass";
myObj.id = "someID";
6个回答

来自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
@Michael 正确 - 如果您使用 setAttribute 设置值,则必须使用 getAttribute 来检索它。
2021-03-15 04:11:26
这大多是错误的。有些属性定义了属性,所以不要。这真的只是关于他们如何编写规范。这与属性是否标准无关。但是,确实只能使用 getAttribute() 访问非标准属性。
2021-03-27 04:11:26
此外,它出现在您的示例中的最后一个 setAttribute 之后,node.frameborder未定义,因此您必须 getAttribute 才能取回该值。
2021-03-28 04:11:26
frameBorder直接设置没有问题,但注意大小写。有人认为将 HTML 属性的 JavaScript 等价物以驼峰命名法是一个好主意。我还没有找到任何关于此的规范,但网络似乎同意这是 12 个特定案例(至少对于 HTML 4)的问题。例如,请参阅以下帖子:drupal.org/node/1420706#comment-6423420
2021-04-02 04:11:26
usemap为图像动态创建地图时,无法使用点表示法设置属性。它需要img.setAttribute('usemap', "#MapName");您的回答是否意味着usemap“非标准”?
2021-04-03 04:11:26

以前的答案都不完整,而且大多数都包含错误信息。

在 JavaScript 中可以通过三种方式访问​​ DOM元素的属性只要您了解如何使用它们,这三者都可以在现代浏览器中可靠地工作。

1. element.attributes

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

请注意,尽管 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不需要访问的地方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>

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

可以使用 DOM 对象上的便捷属性访问许多属性。给定对象上存在哪些属性取决于对象的 DOM 节点类型,而不管 HTML 中指定了哪些属性。可用属性定义在相关 DOM 对象的原型链中的某处。因此,定义的特定属性将取决于您正在访问的元素类型。

例如,className并且id被定义Element和存在是所有元素均DOM节点上,而不是文字或注释节点。value更狭义的定义。它仅适用于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 等)不遵守甚至早于规范。如果您需要支持旧的(损坏的)浏览器,您将需要比此处提供的更多信息。

该问题旨在深入了解哪些方法通常最适合使用。这能回答这个问题吗?
2021-03-13 04:11:26
感谢您解决这个问题。我很好奇,哪些版本的 IE 被认为是“现代的”并遵循 HTML 规范?
2021-03-19 04:11:26
@jkdev IE 永远不会变得现代。什么东西都会变老。
2021-04-03 04:11:26
感谢您提供如此详细的答案,我阅读了很多关于 DOM 和继承的内容,例如 HTMLElement 继承自 Element 等等,您的回答非常有道理。
2021-04-03 04:11:26

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

当您希望按原样处理 DOM(例如仅文本文本)时,请使用getAttribute/ setAttribute不同的浏览器混淆了两者。请参阅Quirks 模式:attribute (in)compatibility

你的意思是 outterHTML* :)
2021-03-15 04:11:26
@Aerovistae - 同意你的看法。添加了一个新答案,希望它更清楚。
2021-03-20 04:11:26
我发现 a.href 返回完整 url,但 getAttribute('href') 返回该属性中的内容(<a href="/help" ...)。
2021-03-25 04:11:26
这个答案有误导性。getAttribute/setAttribute不处理文字。它们只是访问相同信息的两种方式。在下面查看我的答案以获得完整的解释。
2021-04-03 04:11:26
但是如果要影响元素的innerHTML,就必须使用setAttribute...
2021-04-07 04:11:26

我发现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"
你确定没有 ariaLabel 吗?
2021-03-15 04:11:26
@jgmjgm 我刚刚在<select>带有aria-label="...". x.ariaLabel适用于 Chrome,但适用undefined于 Firefox。
2021-03-27 04:11:26
@Antimony 这很奇怪,但是是的,你 100% 正确,我会投票
2021-04-03 04:11:26
实际上并不是真的在 Javascript 中你可以这样做 x["aria-label"]
2021-04-04 04:11:26
@fareednamrouti 那行不通。我刚刚测试了它。JS 属性不影响 html 属性。你真的需要 setAttribute 在这里。
2021-04-08 04:11:26

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

首先,您必须记住 anHTMLElement是一个 Javascript 对象。像所有对象一样,它们具有属性。当然,您可以在内部创建一个几乎任何您想要的名称的属性HTMLElement,但它不必对 DOM(页面上的内容)做任何事情。点符号 ( .) 用于属性现在,有一些特殊的属性映射到属性,并在当时或写,只有4所保证的(稍后更多)。

所有HTMLElements 都包含一个名为 的属性attributesHTMLElement.attributes是一个与 DOM 中的元素相关活动 NamedNodeMap对象。“活”意味着当节点在 DOM 中发生变化时,它们在 JavaScript 端发生变化,反之亦然。在这种情况下,DOM 属性是有问题的节点。ANode具有.nodeValue您可以更改属性。NamedNodeMap对象有一个调用的函数setNamedItem,您可以在其中更改整个节点。也可以直接通过key访问节点。例如,你可以说.attributes["dir"]which 与.attributes.getNamedItem('dir');(side note, NamedNodeMapis case-insensitive, so you can 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 || ''

}

因此,您可以通过dir6 种方式更改属性:

  // 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的所有属性,但只diridlang,并className与方法#6。

HTMLElement 的扩展

HTMLElement具有这 4 个特殊属性。一些元素是HTMLElement具有更多映射属性的扩展类例如,HTMLAnchorElementHTMLAnchorElement.hrefHTMLAnchorElement.relHTMLAnchorElement.target但是,请注意,如果您在没有这些特殊属性的元素上设置这些属性(例如在 a 上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 基本上,按顺序:

  1. 自定义属性,因为它们不影响 DOM 并且不是属性
  2. 浏览器提供的特殊映射 ( dir, id, className)。
  3. 如果属性已经存在element.attributes.ATTRIBUTENAME.nodeValue =
  4. 设置属性();
  5. 如果属性已经存在element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
  6. element.attributes.ATTRIBUTENAME = newNode
  7. element.attributes.setNamedItem(ATTRIBUTENAME) = newNode

结论 (TL; DR)

  • 从使用特殊的属性映射HTMLElementelement.direlement.idelement.className,或element.lang

  • 如果您 100% 确定该元素是HTMLElement具有特殊属性的扩展,请使用该特殊映射。(您可以使用 进行检查if (element instanceof HTMLAnchorElement))。

  • 如果您 100% 确定该属性已存在,请使用element.attributes.ATTRIBUTENAME.nodeValue = newValue.

  • 如果没有,请使用setAttribute().

您提到了这四个属性映射:dir、id、className 和 lang。classList 呢?classList 是保证存在的属性映射吗?
2021-03-11 04:11:26
<input> 和 <textarea> 标签上的 .value 怎么样?它们是什么种类?
2021-03-27 04:11:26
答案中提到的就是 W3C 所说的“反映 IDL 属性”。当您更改 时.value,您正在更改 的内部值,HTMLInputElement然后该值会反映在属性上。他们也不必是string.valueAsNumber会在value 内部发生变化,它的string形式将出现在value属性中。 developer.mozilla.org/en-US/docs/Web/HTML/Attributes
2021-04-04 04:11:26
classList100% 保证存在,但它不是字符串属性,它是一个活动DOMTokenList对象。.className直接设置比操作快classList,但你会覆盖整个事情。
2021-04-08 04:11:26