# はじめに
このイベントの発火順序には、いつも悩まされてきました。
ボタンをclickした時とか、テキストを選択した時のmouseupイベントを拾うリスナー登録で、発火順序をよく調べていなかったため、いつもあいまいのまま、プログラミングをしていました。
まさか、順序が決まっていたとは思わず、自分のプログラミング上の問題と思っていました。試行錯誤してプログラミングして何とか動作していたので、調べもせずにそのままにしていました。
# しかし、いつも問題を起こしていました。
なぜか、mouseupイベントが先に発火しているのです。本当なのか、テストプログラムで確認してみました。
//content.jsの先頭に配置してテスト
$("body").click((e)=>{
alert("clickイベント");
});
$("body").mouseup((e)=>{
alert("mouseupイベント");
});
簡単なプログラムですが、プラグインのcontent.jsの先頭にこのコードを置いて、実行させてみると、やはり、mouseupイベントが先に発火します。
# AIアシスタントに質問しました。
困ったときの神頼みで、最近はAIアシスタントに質問するようにしています。
clicklとmpuseupイベントは、どちらが先に発火するのか
AIアシスタント
AIが回答を生成中AIアシスタント
マウス操作の順番ってややこしいですよね。JavaScriptのイベント順序は決まっているので、整理しておきましょう。
🖱 発火順序の結論
通常の左クリックの場合、ブラウザでは次の順番でイベントが発火します。
mousedown
mouseup
click
つまり、mouseup が先に発火して、そのあとに click が発火します。
🔍 もう少しだけ補足
click は「押して離す」動作が完了したときに発火するイベントです。
そのため、mousedown と mouseup の両方が起きて、なおかつキャンセルされなかった場合に click が発生します。
長押しやドラッグ、右クリックなどでは挙動が変わることがありますが、通常の左クリックなら上記の順序と考えて問題ありません。
👉 実際にコードで確認できるサンプルも用意できますが、今使っているのはブラウザ環境ですか、それともフレームワーク(Reactなど)上での挙動が知りたい感じでしょうか?
素のJavaScript(ブラウザ)でのサンプルが見たい
Reactなどライブラリ上でのイベント順序を知りたい
# 感想
このような答えが返ってきました。
やはり、思っていた通りです。mouseupイベントが先に発火するとのことです。
これで、これからプログラミングするときには悩まずに済みます。AIアシスタントは本当にすばらしいアシスタントです。
# もうひとつ、重要な質問/回答があります。
「なぜか、mouseupイベントが先に発火しているのです。」
これを、AIアシスタントに聞いてみると、いろいろなケースで間違って解釈していたことがわかります。
なぜか、mouseupイベントが先に発火しているのです。
AIアシスタント
AIが回答を生成中AIアシスタント
マウス周りのイベント順がおかしく見えると、かなり混乱しますよね。状況を少し整理してみましょう。
🖱 基本のイベント順
ブラウザでは、通常は次の順で発火します。
mousedown
mouseup
click
dblclick(ダブルクリック時のみ)
なので「mouseup が mousedown より先に発火する」というのは、文字通りそうなっているわけではなく、次のような要因で“そう見えている”ことが多いです。
🔍 よくある原因
コンソールログの行が紛らわしい
例えば次のようなコードだとします。
js
element.addEventListener('mousedown', () => {
console.log('down');
});
element.addEventListener('mouseup', () => {
console.log('up');
});
この場合は必ず down → up の順に表示されます。
もし逆に見えるなら、次のようなことが起きている可能性があります。
mousedown は別の要素についている
キャプチャリングフェーズとバブリングフェーズを混同している
stopPropagation や preventDefault によって、どれかのイベントがキャンセルされている
pointerdown / pointerup など別のイベントも混ざっている
キャプチャリングとバブリング
addEventListener の第3引数またはオプションで capture: true を指定していると、イベントの「通り道」が変わります。
js
element.addEventListener('mouseup', handler, { capture: true });
このようにしていると、
親要素のキャプチャリングフェーズの mouseup が、子要素のバブリングフェーズの mousedown より先にコンソールに出て「順番が逆」に見えることがあります。
フォーカスやドラッグの影響
入力欄やボタン、ドラッグ可能要素などでは、ブラウザ側で独自の処理が入り、
click や mouseup が別のタイミングで発火しているように感じることがあります。
例えば次のようなケースです。
mousedown した瞬間に要素が削除されたり、display: none になっている
mousedown でフォーカス移動や選択範囲の変更が行われている
ドラッグ開始で別のイベントリスナが実行されている
🧪 切り分けのための最小コード
原因を切り分けるには、できるだけシンプルなコードで確認するのが一番早いです。
html
<div id="box" style="width:100px;height:100px;background:skyblue;">
box
</div>
<script>
const box = document.getElementById('box');
box.addEventListener('mousedown', e => {
console.log('down', e.target, e.eventPhase);
});
box.addEventListener('mouseup', e => {
console.log('up', e.target, e.eventPhase);
});
</script>
このような「一つの要素だけ」「capture: true なし」で試してみて、
ここでは順番が正常かどうかをまず確認します。
正常なら、実際のコードとの違いを一つずつ足していくと、どこでおかしくなるかが見つけやすくなります。
# あとがき
先にも述べましたが、困ったときの神頼みで、「AIアシスタント」には助かっています。
# 補足
このあとで、わかったことですが、数年前にすでにQiitaに投稿されていました。以下がそのリンクです。
@zinc0765
(蛍光灯)さんのリンクです。