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


234

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

例えば:

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

または

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

1
からに切り替える.setAttribute()[key] = value、すべてが魔法のように機能し始めました。
Andrew

回答:


73

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

DOMをそのまま扱いたい場合はgetAttribute/を使用してくださいsetAttribute(例:リテラルテキストのみ)。異なるブラウザは2つを混同します。Quirksモード:属性(非)互換性を参照してください。


127
この答えは十分に明確ではありません...私はこれをまだ理解しているとは本当に思っていません。
temporary_user_name

1
@Aerovistae-これに同意します。うまくいけばより明確な新しい答えを追加しました。
オラン2014年

1
ただし、要素のinnerHTMLに影響を与えたい場合は、setAttributeを使用する必要があります...
Michael

3
あなたはoutterHTML *を意味します:)
megawac

4
a.hrefが完全なURLを返すことがわかりましたが、getAttribute( 'href')はその属性(<a href = "/ help" ...)の内容を正確に返します。
プラスチック製のウサギ

144

Javascriptを: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

2
さらに、例の最後のsetAttributeの後にnode.frameborder定義されているため、定義されていないため、値を取得するにはgetAttributeを使用する必要があります。
Michael

5
@Michael正解-setAttributeを使用して値を設定する場合は、getAttributeを使用して値を取得する必要があります。
オラン14

3
frameBorder直接設定しても問題はありませんが、大文字の使用に注意してください。誰かが、HTMLの属性に相当するJavaScriptをキャメルケースに入れるのはおもしろいアイデアだと思っていました。私はこれについての仕様を見つけることができませんでしたが、ネットはそれが12の特定のケースの問題であることに同意しているようです(少なくともHTML 4の場合)。たとえば、次の投稿を参照してください:drupal.org/node/1420706#comment-6423420
aaaaaaaaaaaa

1
usemap画像のための動的マップを作成する場合、属性は、ドット表記法を使用して設定することができません。それimg.setAttribute('usemap', "#MapName");はあなたの答えusemapが「非標準」であることを意味しますか?
mseifert 2016

1
これはほとんど間違っています。一部の属性にはプロパティが定義されているため、定義しません。それは本当に彼らが仕様を書いた方法についてだけです。これは、属性が標準であるかどうかに起因するものです。ただし、標準以外のプロパティにはgetAttribute()でのみアクセスできることは事実です。
ベン

79

以前の回答はどれも完全ではなく、ほとんどが誤った情報を含んでいます。

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

1。 element.attributes

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

DOMオブジェクトの便利なプロパティを使用して、多くの属性にアクセスできます。存在する属性は、HTMLで定義されている属性ではなく、DOMノードのタイプによって異なります。プロパティは、問題の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のどのバージョンが「モダン」と見なされ、HTML仕様に準拠していますか?
jkdev 2016年

3
@jkdev IEが最新のものになることはありません。それが古くなるために何ができるか。
Suraj Jain

このような詳細な回答に感謝します。HTMLElementがElementから継承するなど、DOMと継承についてたくさん読んだので、あなたの答えは完全に理にかなっています。
Suraj Jain

16

setAttribute対応するプロパティがないため、ARIA属性を変更する場合に必要となる1つのケースが見つかりました。例えば

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ではないので、これを行うことができますx ["aria-label"]
Fareed Alnamrouti 2015

@fareednamroutiうまくいきません。私はそれをテストしました。JSプロパティはhtml属性に影響しません。ここでは本当にsetAttributeが必要です。
アンチモン2015

@Antimonyこれは奇妙ですが、はい、100%
正解です。

2
ariaLabelがないことを確認しますか?
jgmjgm 2018年

8

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

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

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

同様の機能は直接ありますHTMLElementあなただけを呼び出すことができる場所setAttributeであろう、自動的にノードを作成し、それが存在し、設定されていない場合nodeValue。などの特別なプロパティを介してプロパティとして直接アクセスできるいくつかの属性もあります。これがどのように見えるかの大まかなマッピングは次のとおりです。HTMLElementdir

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あり、さらにマッピングされたプロパティがあります。たとえば、HTMLAnchorElement持ってHTMLAnchorElement.hrefHTMLAnchorElement.relHTMLAnchorElement.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)

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

  • 100%の場合、要素は拡張されています HTMLElement特別なプロパティでているその特別なマッピングを使用します。(で確認できますif (element instanceof HTMLAnchorElement))。

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

  • そうでない場合は、を使用してくださいsetAttribute()


dir、id、className、およびlangの4つのプロパティマッピングについて説明しました。classListはどうですか?classListは、存在することが保証されているプロパティマッピングですか?
Barzee

classList100%存在することが保証されていますが、これは文字列プロパティではなく、ライブDOMTokenListオブジェクトです。.className直接設定することは、を操作するよりも高速classListですが、全体を上書きすることになります。
ShortFuse

<input>および<textarea>タグの.valueはどうですか?彼らは何ですか?
ダニエルウィリアムズ

回答で言及されているのは、W3Cが「IDL属性を反映する」と呼んでいるものです。を変更.valueすると、の内部値が変更HTMLInputElementされ、属性に反映されます。彼らはまたする必要はありませんstring内部.valueAsNumber変更され、そのフォームが属性に表示されます。 developer.mozilla.org/en-US/docs/Web/HTML/Attributesvalue stringvalue
ShortFuse

3

「JavaScriptでsetAttributeと.attribute =を使用する場合」

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

..それがブラウザーで動作する場合は、問題ありません。

それは、使用していません..If .setAttribute(attribute, value)の代わりを.attributeするためにその属性。

すべての属性のすすぎを繰り返します。

まあ、もしあなたが怠惰なら、あなたは単に使うことができます.setAttribute。ほとんどのブラウザで問題なく動作するはずです。(ただし、をサポート.attributeするブラウザはを最適化できます.setAttribute(attribute, value)。)


0

これは、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);
}

2
このtomo7を共有してくれてありがとう。もう少し説明してください。するposElem.style = newStyleすべてのブラウザで動作ない(Firefoxで動作した)setAttribute再描画を避けて、パフォーマンス上の理由からだけですか?でposElem.style.cssText = newStyle、より多くのperfomrant posElem.style = newStyle
Noitidart 16

0

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

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

そして、setAttributeNodeはsetAttributeを使用するよりも約3倍速いようです。

パフォーマンスに問題がある場合-「setAttributeNode」を使用してください


クロムでテストを実行すると思います。私はMacでChrome、Safari、Firefoxを使用していた。おそらく3人は3つの異なる結果を示した。
Olgun Kaya 2017

0

からの興味深いテイクアウト Google APIスクリプトこれに関する:

彼らはこのようにします:

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

注意、彼らがどのように使うか setAttribute「src」と「nonce」.async = ...、「async」属性。

100%確信はありませんが、おそらく「非同期」はダイレクトをサポートするブラウザでのみサポートされているためです .attr =割り当てです。したがって、sestAttribute("async")ブラウザが理解しない場合、.async=...「非同期」属性を理解しないため、試行しても意味がありません。

うまくいけば、それは私の進行中の「Un-minify GAPI」研究プロジェクトからの有用な洞察です。私が間違っていたら訂正してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.