jQuery 開いたモーダル以外をクリックするとモーダルを閉じる

タイトルの通りなんですけれども、案外ハマったのでちょっと書いておこうかと思います。
ちなみに、モーダルは以下のcodepenのサンプルで言う所の赤いブロックです。

See the Pen jQuery モーダルウィンドウ以外をクリックすると閉じる by Hidekichi (@Hidekichi) on CodePen.

どうやってクリックした箇所から指定要素かそれ以外かを判断するか

例えば単純に何かをクリックするというような動作は、

こんな感じになります。何をクリックしたかは、$(セレクタ)なわけですけれども、例えばこのセレクタがdocumentの場合はどうでしょうか?

この場合は、documentがクリックされているので、どこと言われた場合はdocumentなわけです。しかしながら、それがどこかを特定することは可能です。

こうすることで、どこをクリックしているかがわかると思います。
e.targetを$(e.target)とすることで、jQueryオブジェクトを得ることができます。firefoxでは、

Object { 0: <div.wrapper>, context: <div.wrapper>, length: 1 }

こういう感じで取得できています。つまり、$(e.target).get(0)なら、

が取得できるということです。しかし、このe.targetというやつは、左クリックでも右クリックでも他のボタンでも、クリックした時のターゲットを取得してしまうので、そこらを厳密にする場合は、

このようにすると左クリックの時のみconsole.logを出力します。whichの部分は1: 左クリック、2: 中クリック、3: 右クリックこんな感じになってます。で、ここに、状態を操作する条件式を書いていくわけですが、今回モーダルは、

このようなブロックなっていて、デフォルトではwidth, height共に0でopacityも0、visibilityもhiddenになっています。で、要素をclickすると、このブロックにshowを加えて、positionはfixed、width、heightにもサイズを与えてopacity:1、visibilityはvisibleに変えます。
これら.showは、.mdが.showを持っていない時だけに付けたいので、

という感じで調べられます。元々$(document).on(“click”,function(e){…});で調べてますから、.mdが仮に.showを持っていない時(モーダルが表示されていない時)、要素を何かしらクリックするとfalseの処理になるわけですが、どこをクリックしてもモーダルを開く場合は、そのまま処理を書けばよいですし、特定の要素をクリックした場合であれば、例えば

こんな感じにすると、「何か要素をクリックした時、.mdが.showを持っていない時にその要素が.buttonであれば.mdに.showを追加する」と言う感じの処理が書けます。これでモーダルを開くことができました。

さて問題は、それを閉じる時にどうするかです。例えばモーダルをクリックすれば閉じるというのであれば、

こんな感じに書けばイケると思います。では、モーダルには色々と入力することがあってモーダルをクリックすると閉じてしまうとマズイと言う場合もあると思います。jQueryにはイベントのバブリングと言うのがありまして、子要素をクリックしたと思ったらそれを内包している親要素までクリックしていることになったりすることがあります。

e.stopPropagation();を入れることでイベントのバブリングを停止することもできますが、単純に以下の方法ではどうでしょうか?

先祖要素に対象がない場合は閉じる

この場合、「.mdが.showを持っている時(モーダルが開いている時)、クリックしたターゲットの先祖要素に.mdのlength === 0、つまり存在がなければ.mdから.showを取り除く」こんな感じに書けます。これを実現するためには、

こんな感じのhtmlの構造になっているのが必要になるかと思います。場合によっては、jQueryにて、bodyの先頭や最後尾にモーダルのブロックを挿入しても良いかも知れません。

クリックした要素の先祖要素をさかのぼってそこに.mdがない場合は閉じる。モーダル以外の要素にはもちろん.md要素はないと思うので、だいたいの場合はこれでイケると思います。もし、モーダルが全画面のものである場合は、素直にモーダル自体をクリックしたら閉じるというのが良いと思います。

ここで、ひとつ注意点ですが、e.targetはDOM(ドキュメントオブジェクトモデル)で、$(e.target)はjQueryオブジェクトです。

Firefoxで、.wrapperをクリックした時に、それぞれどのような内容が返ってくるかと言いますと、

対象 .wrapper
e.target
$(e.target)
$(e.target).get(0)

※ jQueryで書くと$(e.target).get(0)ですが、$(e.target)[0]でも同じことです。

if (!$.contains( $(“.hoge”)[0], e.target )){…}で書くこともできるんですけれども、なんだか上手く行かないことも多かったので、面倒ですが細かく条件式を書くのが良いように思ったりしています。

サンプルのスクリプト

応用編

実際に何かのサイトで試していないので動作するかはわかりませんけれども、たぶんイケるかと思います。

See the Pen jQuery モーダルウィンドウ以外をクリックすると閉じる[応用] by Hidekichi (@Hidekichi) on CodePen.

別途ひな形となる関数を用意することで、動作するセレクタ等を任意に変更すると言う感じです。
ひな形になる関数があるので、

これだけで最初のサンプルと同じことができます。
dcは「mouseButton、ターゲット、セレクター、発火要素、event」と言う引数を持っています。右クリックにサンプルと同様の機能をもたせる場合(ダイアログ等の抑制はしてませんけれども)は3を設定すれば良いことになります。

e.targetでどこをクリックした時かは判別できるので、異なる色のモーダルを出したい時は、

だけ用意しておいて、

こんな感じでしょうか。
逆に面倒くさいかなぁ。

スポンサーリンク

シェアする

フォローする