JavaScript クリックイベントが子要素でも発動してしまうのを止める方法

JavaScript クリックイベントが子要素でも発動してしまうのを止める方法

JavaScriptでクリックイベントを設定したときに指定した要素と違うところで処理が発動して思うようにいかなかったときの対処方法です。

今回は子要素で発動してしまう場合を想定して書きます。

 

特にボタンにSVGのアイコンを配置した場合などで起こります。ボタンにイベントリスナーを登録したのにSVGまたはPathで発動してしまいます。

原因は「イベントバブリング」だの「キャプチャフェーズ」というフレーズをよく理解できていないから予期せぬ動作が起こっているのですが、今回は難しい説明はしません。

その場しのぎの方法でサクッと解決しましょう。

 

 

確認用サンプル1

<button class="btn_test" style="padding: 20px;">
<svg  height="256pt" viewBox="0 0 512 512" width="256pt" style="background: cornflowerblue;"><path d="m368 512h-309.332031c-32.363281 0-58.667969-26.304688-58.667969-58.667969v-394.664062c0-32.363281 26.304688-58.667969 58.667969-58.667969h309.332031c32.363281 0 58.667969 26.304688 58.667969 58.667969v394.664062c0 32.363281-26.304688 58.667969-58.667969 58.667969zm-309.332031-480c-14.699219 0-26.667969 11.96875-26.667969 26.667969v394.664062c0 14.699219 11.96875 26.667969 26.667969 26.667969h309.332031c14.699219 0 26.667969-11.96875 26.667969-26.667969v-394.664062c0-14.699219-11.96875-26.667969-26.667969-26.667969zm0 0"/><path d="m346.667969 426.667969h-32c-20.589844 0-37.335938-16.746094-37.335938-37.335938v-53.332031c0-20.585938 16.746094-37.332031 37.335938-37.332031h32c8.832031 0 16 7.167969 16 16s-7.167969 16-16 16h-32c-2.945313 0-5.335938 2.386719-5.335938 5.332031v53.332031c0 2.945313 2.390625 5.335938 5.335938 5.335938h16v-6.230469c-6.230469-2.21875-10.667969-8.128906-10.667969-15.105469 0-8.832031 7.167969-16 16-16h10.667969c8.832031 0 16 7.167969 16 16v37.335938c0 8.832031-7.167969 16-16 16zm0 0"/><path d="m213.332031 426.667969c-7.1875 0-13.480469-4.800781-15.421875-11.714844l-26.667968-96c-2.367188-8.511719 2.625-17.320313 11.136718-19.6875 8.449219-2.390625 17.324219 2.621094 19.691406 11.132813l11.261719 40.492187 11.242188-40.492187c2.347656-8.511719 11.179687-13.523438 19.691406-11.132813 8.511719 2.367187 13.503906 11.175781 11.136719 19.6875l-26.667969 96c-1.917969 6.914063-8.210937 11.714844-15.402344 11.714844zm0 0"/><path d="m106.667969 426.667969h-26.667969c-8.832031 0-16-7.167969-16-16s7.167969-16 16-16h26.667969c5.3125 0 10.664062-2.753907 10.664062-8.898438 0-6.183593-6.675781-7.101562-10.664062-7.101562-24.726563 0-42.667969-16.683594-42.667969-39.660157 0-22.976562 18.347656-40.339843 42.667969-40.339843h26.664062c8.832031 0 16 7.167969 16 16s-7.167969 16-16 16h-26.664062c-1.773438 0-10.667969.402343-10.667969 8.339843 0 7.105469 8.171875 7.660157 10.667969 7.660157 24.722656 0 42.664062 16.445312 42.664062 39.101562 0 22.933594-18.730469 40.898438-42.664062 40.898438zm0 0"/></svg>
</button>
<p class="output">クリックすると結果が表示されます。</p>
<script>
let button = document.querySelector(".btn_test");
button.addEventListener("click", e => {
    document.querySelector(".output").innerText = "親要素は => " + e.target.parentNode.nodeName + " 自身の要素は => " + e.target.nodeName;
})
</script>

デモ1

クリックする場所によって結果が変わります。

イベントを登録したのはボタン要素だけですが、子要素のSVGやPATHの上でクリックしても発動します。

このような構造になっています。BUTTON > SVG > PATHという関係です。

イベントに登録した処理から、親要素を取得しようとするとクリックした場所で取得した内容が異なります。

 

 

これを解消するにはボタン直下の<SVG>にCSSのpointer-events: none;を追加するだけです。

サンプル2

<button class="btn_test" style="padding: 20px;">
<svg style="pointer-events: none;" height="256pt" viewBox="0 0 512 512" width="256pt"><path d="m368 512h-309.332031c-32.363281 0-58.667969-26.304688-58.667969-58.667969v-394.664062c0-32.363281 26.304688-58.667969 58.667969-58.667969h309.332031c32.363281 0 58.667969 26.304688 58.667969 58.667969v394.664062c0 32.363281-26.304688 58.667969-58.667969 58.667969zm-309.332031-480c-14.699219 0-26.667969 11.96875-26.667969 26.667969v394.664062c0 14.699219 11.96875 26.667969 26.667969 26.667969h309.332031c14.699219 0 26.667969-11.96875 26.667969-26.667969v-394.664062c0-14.699219-11.96875-26.667969-26.667969-26.667969zm0 0"/><path d="m346.667969 426.667969h-32c-20.589844 0-37.335938-16.746094-37.335938-37.335938v-53.332031c0-20.585938 16.746094-37.332031 37.335938-37.332031h32c8.832031 0 16 7.167969 16 16s-7.167969 16-16 16h-32c-2.945313 0-5.335938 2.386719-5.335938 5.332031v53.332031c0 2.945313 2.390625 5.335938 5.335938 5.335938h16v-6.230469c-6.230469-2.21875-10.667969-8.128906-10.667969-15.105469 0-8.832031 7.167969-16 16-16h10.667969c8.832031 0 16 7.167969 16 16v37.335938c0 8.832031-7.167969 16-16 16zm0 0"/><path d="m213.332031 426.667969c-7.1875 0-13.480469-4.800781-15.421875-11.714844l-26.667968-96c-2.367188-8.511719 2.625-17.320313 11.136718-19.6875 8.449219-2.390625 17.324219 2.621094 19.691406 11.132813l11.261719 40.492187 11.242188-40.492187c2.347656-8.511719 11.179687-13.523438 19.691406-11.132813 8.511719 2.367187 13.503906 11.175781 11.136719 19.6875l-26.667969 96c-1.917969 6.914063-8.210937 11.714844-15.402344 11.714844zm0 0"/><path d="m106.667969 426.667969h-26.667969c-8.832031 0-16-7.167969-16-16s7.167969-16 16-16h26.667969c5.3125 0 10.664062-2.753907 10.664062-8.898438 0-6.183593-6.675781-7.101562-10.664062-7.101562-24.726563 0-42.667969-16.683594-42.667969-39.660157 0-22.976562 18.347656-40.339843 42.667969-40.339843h26.664062c8.832031 0 16 7.167969 16 16s-7.167969 16-16 16h-26.664062c-1.773438 0-10.667969.402343-10.667969 8.339843 0 7.105469 8.171875 7.660157 10.667969 7.660157 24.722656 0 42.664062 16.445312 42.664062 39.101562 0 22.933594-18.730469 40.898438-42.664062 40.898438zm0 0"/></svg>
</button>
<p class="output">クリックすると結果が表示されます。</p>
<script>
let button = document.querySelector(".btn_test");
button.addEventListener("click", e => {
    document.querySelector(".output").innerText = "親要素は => " + e.target.parentNode.nodeName + " 自身の要素は => " + e.target.nodeName;
})
</script>

デモ2

どこでクリックしても同じです。
pointer-events: none;はクリックなどのポインターイベントを止めるので子要素ではイベントが発生しなかったというわけです。

ポインターイベント属性の詳しい解説はドキュメントを確認しましょう。

https://developer.mozilla.org/ja/docs/Web/CSS/pointer-events

 

今回解決に至らなかった場合はこちらも読むと「イベントバブリング」への理解が深まると思います。優しく解説されています。

addEventListener再入門 第1回 バブリングによるイベントの伝播

 

₍ ᐢ. ̫ .ᐢ ₎マダナイ

コメントを残す

メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。URLを含むコメントは承認待ちになります。