はじめに
レスポンシブ対応でよくある、あるボタンを押すとサイドメニューが展開するというものを実装していた。
そこでメニュー部分をクリックしても閉じないが、メニュー外の部分(背景)をクリックするとサイドメニューが閉じるという機能を実装した際、 JavaScriptのイベントのe.target
とe.currentTarget
の違いについても勉強になったのでまとめておく。
※実装したサンプルコードは以下のCodeSandboxです。ぜひ実際に挙動を試してみてください。
実装の概要
JavaScriptのイベントのe.target
とe.currentTarget
の違いを利用して、メニュー外をクリックしたときのみメニューを閉じるように実装する。
target
と currentTarget
の違いは以下の通り。
-
target
: イベントを発生させた要素を取得する(実際にクリックされたDOMを取得する)
Event.target - Web API | MDN -
currentTarget
: イベントハンドラがアタッチされた要素を取得する
Event.currentTarget - Web API | MDN
実装方法
開閉するサイドメニューを実装する
まずは開閉するサイドメニューを実装する。
Reactの基本的な実装なので、詳細の説明は省略してコードのみ載せる。
import { useState } from "react";
export default function App() {
const [isShow, setIsShow] = useState(false);
return (
<div>
<button onClick={() => setIsShow(true)}>Menu</button>
{isShow && (
<div // 画面全体を覆う背景
style={{
backgroundColor: "rgba(0, 0, 0, 0.6)",
position: "fixed",
top: "0px",
zIndex: 1,
width: "100%",
height: "100%"
}}
>
<div // メニュー部分
style={{
backgroundColor: "white",
position: "fixed",
top: "0px",
zIndex: 1,
width: "30%",
height: "100%"
}}
>
<p>Menu</p>
<ul>
<li>Top</li>
<li>Profile</li>
<li>Blog</li>
</ul>
<button onClick={() => setIsShow(false)}>閉じる</button>
</div>
</div>
)}
</div>
);
}
メニューの外をクリックした場合はメニューを閉じる
本題の、
・メニューの内、外のどちらをクリックしたか判定する
・メニュー外をクリックした場合はメニューを閉じる
という部分を実装する。
と言っても記述は非常にシンプルで、メニュー画面全体を覆っている(背景となっている) div
要素に、1行追記するのみ。
<div
// 以下の1行を追記
onClick={(e) => e.target === e.currentTarget && setIsShow(false)}
style={{
backgroundColor: "rgba(0, 0, 0, 0.6)",
position: "fixed",
top: "0px",
zIndex: 1,
width: "100%",
height: "100%"
}}
>
この onClick
イベントは、メニューを開いている際に画面いっぱいに表示される背景に付与しているので、 e.target
には常にこの div
要素が入ることになる。
それに対して e.currenttarget
にはクリックイベントを発生させた要素が入るので、メニュー内をクリックした場合にはメニュー部分の div
要素が、メニュー外(背景)をクリックした場合にはメニュー外(背景)の div
が入ることになる。
これにより、クリックしたのが(つまり e.currentTarget
が)メニュー外の背景だった場合は、サイドメニューを閉じるという機能を実現している。
さいごに
要素外をクリックした場合にメニューを閉じるという機能の実装方法を検索すると色々な方法が見つかったが、私はこの方法が一番シンプルでしっくり来た。
また今回、 [e.target](http://e.target)
と e,currentTarget
の違いの便利さを学んだと同時に、違いを理解していないと意図しない挙動を引き起こしてしまうかもしれないので気を付けないといけないと思った。
ライブラリを使ってモーダルなどを実装すると、モーダル外をクリックするとモーダルを閉じるようにすることも簡単に出来ることが多いが、あれはどういう方法で実装されているのだろうと少し気になった。
参考記事