リサイズによってクリックイベントがおかしくなる場合の対処法

※本ブログの目的は個人の備忘録であり、コードは参考用として掲載しています。
実際に使用される際は、ご自身の環境で十分に動作確認を行ってください。
コードの利用によって生じたいかなる問題についても責任を負いかねますので、あらかじめご了承ください。

レスポンシブ対応の実装において、ウィンドウ幅の変化に応じて JavaScript を再実行したくなるケースは少なくありません。

しかし、特に クリックイベント(click)を resize イベント内で再設定する実装は、多くの場合問題を引き起こします。

もしリサイズ後にクリックイベントが正しく動作しない場合は、本記事の内容を確認することで解決できる可能性があります。

リサイズ時にクリックイベントを再設定する例

以下のコードは一見シンプルで正しく動作しているように見えます。

window.addEventListener("resize", () => {
  const btn = document.querySelector(".menu-btn");
  btn.addEventListener("click", () => {
    console.log("クリックされました");
  });
});

しかし、この実装には重大な欠陥があります。

resize が発生するたびに、新しいクリックイベントリスナーが追加されるため、クリック1回で複数回処理が実行される状態になります。

問題の発生原因

addEventListener() は既存のリスナーを上書きせず、同じ要素・同じイベントでも新しいリスナーを追加します。

そのため、リサイズが頻繁に発生すると、次のような問題が発生します。

  • クリックイベントが重複して発火する
  • パフォーマンスの低下やメモリ使用量の増加
  • UI の状態が意図せず変更されることによる不整合

クリックイベントは、初期化時に一度だけ登録するのが原則です。

関数化した初期化処理とリサイズ

開発者の多くは、イベント登録や DOM 操作を関数としてまとめ、リサイズ時に再実行する設計を行います。

function initMenu() {
  const btn = document.querySelector(".menu-btn");
  btn.addEventListener("click", toggleMenu);
  const panel = document.querySelector(".menu-panel");
  panel.style.height = "auto";
}

// リサイズ時に呼び出す
window.addEventListener("resize", initMenu);

この場合も、クリックイベントが重複登録されるという問題は同様に発生します。

リサイズによりクリックイベントが重複して登録されると、開閉トグルが同時に発生し、結果として正常に動作しなくなる場合があります。

実装方法

1. 初期化時にイベントを登録する

クリックイベントは、初期化時に一度だけ登録するのが原則です。

// クリックイベントは初期化時に1度だけ登録する
function initMenu() {
  const btn = document.querySelector(".menu-btn");
  btn.addEventListener("click", toggleMenu);
}

window.addEventListener("DOMContentLoaded", initMenu);

2. リサイズ時は状態のリセット・調整のみ

リサイズ時には、イベントの再登録ではなく、表示状態やレイアウトのみを調整します。

window.addEventListener("resize", () => {
  // 状態の調整
  if (window.innerWidth > 640) {
    closeMenu();
  }
  adjustPanelHeight();
});

再登録がどうしても必要な場合

基本的には避けるべきですが、やむを得ず再登録する場合は、removeEventListener() を利用して既存のリスナーを削除してから追加します。

function handleClick() {
  toggleMenu();
}

btn.addEventListener("click", handleClick);

window.addEventListener("resize", () => {
  btn.removeEventListener("click", handleClick);
  btn.addEventListener("click", handleClick);
});

まとめ

  • resize イベント内でクリックイベントを再設定すると、イベントが重複し、パフォーマンス低下や不具合の原因となる
  • 初期化関数をまとめることは良い設計だが、リサイズ時に再実行すると副作用が発生する
  • 正しいアプローチは、イベントは初期化時に1回だけ登録し、リサイズ時には表示状態やレイアウトを調整すること
  • 状態管理や条件分岐を活用することで、安全かつ安定したレスポンシブUIを実現できる

リサイズ時のイベント登録は、思わぬバグの温床になります。

JavaScript におけるイベント設計では、登録タイミングと実行範囲を明確にすることが重要です。