web-dev-qa-db-ja.com

JavaScriptでsetAttribute vs .attribute =を使用する場合

ドット(.)属性表記の代わりにsetAttributeを使用することに関するベストプラクティスが開発されましたか?

例えば。:

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

または

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

JavaScriptでプログラムによるアクセスが必要な場合は、常に直接.attributeフォームを使用する必要があります(ただし、以下のquirksmodeリンクを参照してください)。さまざまなタイプの属性を正しく処理する必要があります(「onload」と考えてください)。

DOMをそのまま処理する場合は、getAttribute/setAttributeを使用します(例:リテラルテキストのみ)。異なるブラウザーはこの2つを混同します。 Quirksモード:attribute(in)compatibility を参照してください。

66
user166390

Javascript:The Definitive Guide から、物事を明確にします。 HTMLElement HTMLドキュメントのオブジェクトは、すべての標準HTML属性に対応するJSプロパティを定義していることに注意してください。

したがって、非標準の属性に対してのみsetAttributeを使用する必要があります。

例:

node.className = 'test'; // works
node.frameborder = '0'; // doesn't work - non standard attribute
node.setAttribute('frameborder', '0'); // works
127
olan

これまでの回答はいずれも完全ではなく、ほとんどに誤情報が含まれています。

JavaScriptでDOM Element の属性にアクセスするには、3つの方法があります。これら3つはすべて、最新のブラウザーで使用方法を理解している限り、確実に機能します。

1. element.attributes

要素には、ライブ NamedNodeMap of Attr オブジェクトを返すプロパティ attributes があります。このコレクションのインデックスはブラウザによって異なる場合があります。そのため、順序は保証されません。 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.getAttributeelement.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. element.idなどのDOMオブジェクトのプロパティ

DOMオブジェクトの便利なプロパティを使用して、多くの属性にアクセスできます。存在する属性は、HTMLで定義されている属性ではなく、DOMノードのタイプによって異なります。プロパティは、問題のDOMオブジェクトのプロトタイプチェーンのどこかで定義されます。定義されている特定のプロパティは、アクセスしている要素のタイプによって異なります。たとえば、classNameidElementで定義され、要素であるすべての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仕様がどのように定義し、最新のブラウザーが属性を処理するかの説明です。私は、古くて壊れたブラウザの制限に対処しようとしませんでした。古いブラウザをサポートする必要がある場合は、この情報に加えて、それらのブラウザで何が壊れているかを知る必要があります。

67
Ben

setAttributeが必要なケースの1つは、対応するプロパティがないため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"
14
Antimony

これらの答えは、実際にはpropertiesattributesの間の大きな混乱に対処していません。また、Javascriptプロトタイプによっては、要素のプロパティを使用して属性にアクセスできる場合とできない場合があります。

まず、HTMLElementはJavascriptオブジェクトであることを覚えておく必要があります。すべてのオブジェクトと同様に、プロパティがあります。もちろん、HTMLElementの中に必要なほぼすべてのプロパティを作成できますが、DOM(ページ上にあるもの)で何もする必要はありません。ドット表記(.)は、properties用です。現在、属性にマップされる特別なプロパティーがいくつかあります。また、現時点では、保証されているのは4つだけです(詳細は後述)。

すべてのHTMLElementsには、attributesというプロパティが含まれています。 HTMLElement.attributesは、DOMの要素に関連するliveNamedNodeMapオブジェクトです。 「ライブ」とは、DOMでノードが変更されると、JavaScript側でノードが変更され、その逆も同様であることを意味します。この場合、DOM属性は問題のノードです。 Nodeには、変更可能な.nodeValueプロパティがあります。 NamedNodeMapオブジェクトには、ノード全体を変更できるsetNamedItemという関数があります。キーでノードに直接アクセスすることもできます。例えば、.attributes.getNamedItem('dir');と同じ.attributes["dir"]と言うことができます(補足:NamedNodeMapは大文字と小文字を区別しないため、'DIR'を渡すこともできます)。

同様の関数がHTMLElementに直接あり、そこでsetAttributeを呼び出すことができます。これはノードを自動的に作成する存在しない場合はnodeValueを設定します。また、特殊プロパティを介してHTMLElementのプロパティとして直接アクセスできるsome属性(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 || ''

}

したがって、dir属性を6つの方法で変更できます。

  // 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ではdiridlang、およびclassNameのみを更新できます。

HTMLElementの拡張

HTMLElementには、これらの4つの特別なプロパティがあります。一部の要素は、HTMLElementの拡張クラスであり、さらにマッピングされたプロパティがあります。たとえば、HTMLAnchorElementにはHTMLAnchorElement.hrefHTMLAnchorElement.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 。基本的に、順番に:

  1. カスタムプロパティはDOMに影響を与えず、属性ではないためです
  2. ブラウザが提供する特別なマッピング(diridclassName)。
  3. 属性が既に存在する場合element.attributes.ATTRIBUTENAME.nodeValue =
  4. setAttribute();
  5. 属性がすでに存在する場合element.attributes.getNamedItem(ATTRIBUTENAME).nodeValue = newValue
  6. element.attributes.ATTRIBUTENAME = newNode
  7. element.attributes.setNamedItem(ATTRIBUTENAME) = newNode

結論(TL; DR)

  • HTMLElementからの特別なプロパティマッピングを使用します:element.direlement.idelement.className、またはelement.lang

  • エレメントが特別なプロパティを持つ拡張HTMLElementであることを100%確信している場合、その特別なマッピングを使用します。 (if (element instanceof HTMLAnchorElement)で確認できます)。

  • 属性がすでに存在することを100%確信している場合は、element.attributes.ATTRIBUTENAME.nodeValue = newValueを使用します。

  • そうでない場合は、setAttribute()を使用します。

2
ShortFuse

「JavaScriptでsetAttribute vs .attribute =を使用するタイミング」

一般的なルールは、.attributeを使用し、それがブラウザで動作するかどうかを確認することです。

..ブラウザで動作する場合は、準備完了です。

..そうでない場合は、that属性に.attributeの代わりに.setAttribute(attribute, value)を使用します。

すべての属性に対してリンスを繰り返します。

怠け者の場合は、.setAttributeを使用できます。それはほとんどのブラウザでうまくいくはずです。 (.attributeをサポートするブラウザは、.setAttribute(attribute, value)よりも最適化できます。)

2
Pacerier

要素に属性(クラスなど)を設定するためのメソッド:1. el.className = string 2. el.setAttribute( 'class'、string)3. el.attributes.setNamedItem(object)4. el.setAttributeNode(node)

簡単なベンチマークテストを行いました( here

また、setAttributeNodeはsetAttributeを使用した場合よりも約3倍高速であるようです。

パフォーマンスが問題になる場合-「setAttributeNode」を使用

0
Yair Levy

これは、setAttributeを使用したほうが良い場合の1つです。

Dev.Opera —効率的な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);
}
0
tomo7