【JavaScript】class取得をしてaddEventListenerでイベント処理をする際にハマった二つの落とし穴

こんにちは。ロジカルスタジオのノートです。

以前、JavaScriptを書いていて、

「class名が同じものを全て取得してそれぞれにイベント処理を行う」

ということに大きく、大きく、躓いてしまいました。

今回は、簡易的なドロップダウンメニューを作成していきながら失敗例と共に解説することで、

このようなことで、丸一日費やしてしまう人を1人でも減らしたいと思っています。

最初に書いたコード(失敗例)

まずは、classを取得して「マウスが乗ったら表示・マウスが離れたら非表示」という処理をしたかったので、このように書きました。

See the Pen drop-down-menu-demo-1 by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

ですが、要素は微動だにしません。

動かなかった理由

「最初に書いたコード(失敗例)」が動かなかった理由は下の二つです。

  1. addEventListenerで全ての要素にイベント処理をかけれていない
  2. 戻り値が配列ではない

では、一つずつ解説していきます。

addEventListenerで全ての要素にイベント処理をかける

まず、addEventListenerで全てのclassに処理をかけて!と言っていないことが原因です。

なので、forEach文の繰り返し処理を使って、配列の全てに処理をかけて!と言ってやる必要があります。

See the Pen drop-down-menu-demo-3 by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

しかし、やってみたところ全然反応してくれません。

なぜでしょうか。反抗期でしょうか。

戻り値が配列ではない

次に、なぜ下のコードで動かないのかを解説します。

var trigger = document.getElementsByClassName("trigger");

それは、「document.getElementsByClassName」で取ってくる時の戻り値の正体が、

HTMLCollection」だからです。配列のようで配列ではない配列のようなものなのです。

そして、残念ながらその配列のようなものである「HTMLCollection」ではforEarchが動いてくれないのです。

何故ならそれは、「HTMLCollection」であり、配列ではないからです。

大事なので二回言いました。

では、HTMLCollectionを無理やり配列にしてやれば良いんではないかということで、

Array.fromというメソッドを使って配列にしてやります。

var triggers = Array.from(trigger);

こう書けば配列として変換されます。ということで、配列にしてみます。

完成したコード

See the Pen drop-down-menu-demo-4 by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

できました。

配列化してみて、trigger(class)を持っている要素にカーソルを合わせると正しく子要素が表示されます。

どうやらこれで完成のようです。

「document.querySelectorAll」という便利技

先程、classの取得をする際に「わざわざ配列にする」という作業を行いましたが、

実は、そのようなことをしなくても「querySelectorAll」というメソッドがあります。

このメソッドはDOM操作をjQueryのように行うことができる便利なもので、

「querySelectorAll」で取得すると、戻り値が「HTMLCollection」ではなく「NodeList」になります。

なので、簡単に配列化してforEachで回し、取得することができてしまいます。

See the Pen drop-down-menu-demo-6 by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

このように、わざわざ配列に変換せずとも「querySelectorAll」なら動いてくれます。

そう、「querySelectorAll」ならね。

どうやら「NodeList」も「HTMLcollection」と同様に、配列のようなもののようですが、forEach文は使えるようです。。

まとめ

今回落っこちてしまった落とし穴をまとめると、

  1. 全てのclassにaddEventListenerでイベント処理をかけたい時は繰り返し処理を使う
  2. 「document.getElementsByClassName」の戻り値は「HTMLCollection」

です。皆さんも気をつけてください。

今回、僕が解説したところは、

JavaScriptで全ての同classを操作をする際に、高確率でハマってしまうポイントだと思います。

特に僕のようなjQueryから入った人は、特にハマりやすい気がします。jQueryでのDOM操作は「$」があれば万事解決ですから。

その上、「配列」や「繰り返し処理」と言われて、頭に「?」が浮かんでしまう人に取っては何がなんやらという感じだろうと思います。

なので、今回は噛み砕いて解説してみました。

ちなみに、黙ってjQueryを使っておけばこれだけの記述量で書けてしまいます。

See the Pen drop-down-menu-demo-5 by LOGICAL STUDIO PR部 (@ls_pr) on CodePen.

DOMの操作性に関してはやはりjQueryは強いです。

ライブラリというものは便利ですね。。