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) => {
// ...
}
));
そこそこコードが長くなりますがイベントハンドラを別メソッドとして定義しておくなどすれば一行で書けなくもない長さです。
data-roleなど適当なプロパティを設定してquerySelectorAll
ふたつめ。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