HTML上の複数要素に一括してイベントハンドラを設定する
HTML要素にJavaScriptでイベントハンドラを設定する場合、基本的には次のように、IDを指定してノードを選択して、addEventListener()
メソッドを使います。
document.getElementById("id").addEventListener("click", (e) => {
// ...
});
ただ同じような挙動を行う要素が複数ある場合など、いちいちひとつひとつのノードにイベントリスナーを設定するのが面倒くさい場合もあると思います。
そんなときにとれる方法としてはふたつ。
- 複数ノードにクラスを設定して
document.getElementsByClassName("クラス名")
でノードリストを取得する - data-roleなど適当なプロパティを設定して
document.querySelectorAll("button[data-role='saveimage']")
などとしてノードリストを取得する
詳しく解説していきます。
getElementsByClassName
複数ノードにクラスを設定してひとつめ。複数のノードにクラスを指定して、そのクラス名をgetElementsByClassName
で読み取り、一括してノードにイベントリスナーを設定する方法。
Array.from(document.getElementsByClassName("class")).forEach((v) => v.addEventListener("click", (e) => {
// ...
}
));
そこそこコードが長くなりますがイベントハンドラを別メソッドとして定義しておくなどすれば一行で書けなくもない長さです。
querySelectorAll
data-roleなど適当なプロパティを設定してふたつめ。HTMLではdata-*
というカスタムデータ属性を定義することが可能です。
ですのでこれを使って、data-role="save"
などといったロールを勝手に設定して、それを指定してquerySelectorAll
で要素リストを取得し処理する方法。
document.querySelectorAll("button[data-role='saveimage']").forEach(v => v.addEventListener("click", (e) => {
// ...
}));
こちらはquerySelectorAll
の戻り値NodeList
にforEach
メソッドがあるので、いちいちArray.from
などと書かなくてもforEach
できます。
このためコードは多少短くなるような気もしますが、ノード名や要素名をちゃんと指定してあげないといけなくなるぶん括弧の中の文が長くなり、結果的に大して変わらない気がします。
また、data-role
要素はclassName
と違って一つのノードに一つしか設定できないぶん、同じボタンに複数の役割を持たせたいなどといった処理には不向きです。
querySelectorAll
でもよさげ
クラスを設定して書いていて気付きましたが、クラス名を指定してquerySelectorAll
でもいいかもしれません。この方がコード自体は短くなりますね。
document.querySelectorAll(".saveimage").forEach(v => v.addEventListener("click", (e) => {
// ...
}));
まあ、クラス名はBootstrapなどでも使うのでどのクラスがどの役割を持っているのかわからなくなりやすいというデメリットはあるかもしれません。
この辺は他の要素の利用状況などを踏まえて一番シンプルな方法を考えるのが良さそうです。
Discussion