asuchi0819さんがおっしゃっているように、同じid属性は1ページ内に一つしか存在してはいけないことになっています。
もし文法を無視して同一idの要素が文書内に複数存在する場合、getElementById
は最初の要素を取得します。(element.id)
そのため、clickハンドラを追加する処理が最初の1つにしかされていないのです。
HTMLのボタンの部分を
<div class="text-button">
<p class="text">クリック</p>
</div>
スクリプトを
<script>
// text-buttonクラスを持つ要素の配列を取得、各要素をforEachでループ処理、elには各要素が順番にわたさ
Array.from(document.getElementsByClassName("text-button")).forEach(function(el) {
// 書き換え対象であるtextクラスを持つ要素を取得
var iel = el.getElementsByClassName("text")[0];
// clickイベントのリスナーを設定
el.addEventListener("click", function() {
iel.innerText = "クリックされた!";
});
});
</script>
としてみてください。
- class属性を使ってElementを取得する場合
getElementsByClassName
メソッドを使います。Element**"s"**であることに注意してください。
getElementsByClassName
はHTMLCollection
を返します。HTMLCollection
はElement
の配列のようなものです。
- jsで配列の各要素にたいして何らかの処理を行う場合、
forEach
メソッドを使うのが一般的です。
- しかし、HTMLCollectionはElementの配列のようなもので、厳密には配列ではありません。なのでforEachは使うことができません。
- そこで
Array.from
を使って、HTMLCollectionを配列に変換します。
- よって、
Array.from(document.getElementsByClassName("text-button"))
は、documentからtext-buttonクラスを持つ要素のHTMLCollectionを取得し、それを配列に変換する = documentからtext-buttonクラスを持つ要素の配列を取得するという意味になります。
forEach
メソッドには関数を渡します。渡した関数にはforEachによって配列の各要素が自動的に渡されます。(今回はtext-buttonクラスを持つElementが順番に1つずつ渡されます。これをelで受けています) 参考
- 書き換える対象となるtextクラスを持つ要素を、getElementsByClassNameで取得します。getElementsByClassNameはたとえ取得した要素が1つでもHTMLCollectionとして返すので、最初の要素
[0]
を取得します。
- el(text-button)に対してイベントリスナーを設定します。この例の場合は、
el.onclick = function(){...}
でも問題ありませんが、この書き方ではtext-buttonのonclickに既に別のイベントリスナーが設定されていた場合、上書きしてしまいます。el.addEventListener("click", function(){...})
を使うと、上書きすることなく追加することができます。
注意点としては、
- dsocument内の全てのtext-buttonクラスを持つ要素に処理を行うので、text-buttonクラスを持つ全く別の要素がdocument内にあった場合、例外になる可能性が高い。(その他の要素がtextクラスを持つ要素を子に持っていないと
TypeError
になります。)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。