問題
querySelectorAll()メゾッドでセレクタを指定して、addEventListener()メゾッドでクリックイベントを仕込もうとしたときです。
const target = document.querySelectorAll('nav a');
const closeNav = function () {
const close = document.getElementById('global-nav');
close.classList.toggle('nav-open');
};
target.addEventListener('click', closeNav);
addEventListener()が動かない…
Uncaught TypeError: target.addEventListener is not a function
どうやらtarget.addEventListenerが関数(function)として認識されていないようです。
querySelector()ではうまく動いたのに…
原因
まずquerySelectorAll()メゾッドのリファレンスを読むと
Document の querySelectorAll() メソッドは、与えられた CSS セレクターに一致する文書中の要素のリストを示す静的な (生きていない) NodeList を返します。
とあります。
文書中の要素のリストを示す静的な (生きていない) NodeList を返す…
さらに、querySelectorAll()メゾッドの返値というNodeListを調べると
NodeList オブジェクトはノードの集合であり、 Node.childNodes などのプロパティや document.querySelectorAll() などのメソッドの返値として用いられます。
NodeList は Array とは異なりますが、 forEach() メソッドで処理を反復適用することは可能です。 Array.from() を使うことで Array に変換することができます。
とありました。
このことから、querySelectorAll() の返値は配列ではないがリスト状になっており、forEach()メゾッドを使えば処理することができるという解釈にいたりました。
解決
const targetList = document.querySelectorAll('nav a');
const closeNav = function () {
const close = document.getElementById('global-nav');
close.classList.toggle('nav-open');
};
targetList.forEach(function (target) {
target.addEventListener('click', closeNav);
});
まずquerySelectorAll() メゾッドの返値はリストということで、targetListという変数名にしました。
そして、targetList内のひとつひとつの要素にaddEventListener()メゾッドが実行されるように、forEach()メゾッドでtargetListを回しました。
無事、エラーが解消され、望んだ動きをしてくれるようになりました。
まとめ
-
querySelectorAll()メゾッドは配列ではないがリスト状のNodeListを返す。 -
forEach()メゾッドでリストの中身ひとつひとつに処理をあてることができる。
