たとえばhtmlの要素が.container > .boxみたいな構造になっていて、.containerが表示されているところだけをクリック可能にしたいなんてときの話。

子要素の.boxをクリックしたときは.containerに仕込んだイベントを発火しないようにしたい。

通常は.containerに仕込んだイベントリスナーは子要素をクリックしたときにも発火してしまう。

この問題を解決したサンプルコードはこちらです。

See the Pen クリックした要素の情報を得る by Makoto Ohnami (@zohnami) on CodePen.

ポイントは.boxの座標をgetBoundingClientRectで取得して、その範囲外のときのみクリック時の処理を実行するようにしたところです。

力技感が出ていますが以下のようにクリック時の座標と突き合わせをして判定をしています。

const box = document.querySelector('.box');
const boxRect = box.getBoundingClientRect();

const container = document.querySelector('.container');
container.addEventListener('click', (event) => {
  if (event['pageX'] < boxRect.left
      || event['pageX'] > boxRect.right
      || event['pageY'] < boxRect.top
      || event['pageY'] > boxRect.bottom) {
    alert('hit !!!!');
  }
});

getBoundingClientRectを使うと、要素の四隅の座標を取得できます。

getBoundingClientRect

イベントリスナーで受け取るeventにはイベントが発生したところの座標が情報として含まれています。

pageXpageYはそのhtmlページ全体(画面に隠れているところも含む)を基準とした絶対座標が格納されています。今回はこちらを使いました。

他にも、以下のリンク先のようにoffsetclientscreenというのがあるようで、その辺は目的に応じて使い分けする感じですね。

毎度おなじみmdn eb docs

そもそも、親要素だけをクリック可能にしたいとかある?って話ですが自分の場合、モーダルを出現させたときにモーダルの背景は半透明のグレーにして、そのグレー領域をタップしたらモーダルを閉じる、みたいなことをやりたくてこの方法にたどり着きました。

もっと良いやり方があるよ、というのがあったら教えてください。

この記事の環境情報

  • Google Chrome 108.0.5359.124
  • なぜだか眠い