JavaScript
この記事では、押していたマウスボタンを離した瞬間に発生するmouseupイベントの基本を説明します。
The 'mouseup' event is fired the moment a user releases a previously pressed mouse button.
mouseup [event]
「mouseup」イベントとは
「mouseup」イベントは、ユーザーがマウスのボタンを押し、押していたボタンを離したとき(マウスボタンを"アップ"したとき)に発生するイベントです。たとえば、左クリックや右クリック、または中クリックのホイールボタンを離した瞬間に反応します。
- mousedown
- ボタンを押したタイミング
- mouseup
- 押したボタンを離したタイミング
- click
- mousedownからmouseupまでが同じ要素で行われた場合に発生
「mouseup」は、クリック動作の後半で発生するイベントであり、DOM操作やドラッグアンドドロップの終了処理などに活用できます。
基本的な使い方
イベントの付与方法
マウスイベントは、通常以下のような方法で要素にイベントリスナーを登録して扱います。
HTMLタグに直接指定する方法(推奨されない場合が多い)
HTML
<button onmouseup="handleMouseUp()">ボタン</button>
<script>
function handleMouseUp() {
console.log("マウスボタンが離されました。");
}
</script>
HTML内に直接イベントハンドラを埋め込む方法です。小規模なスクリプトでは簡単ですが、コードの可読性が下がる、スクリプトがHTMLに混在するなどの理由から大規模開発にはあまり推奨されません。
JavaScriptでイベントリスナーを登録する方法(推奨)
HTML
<button id="myButton">ボタン</button>
<script>
const button = document.getElementById("myButton");
button.addEventListener("mouseup", function(event) {
console.log("マウスボタンが離されました。", event);
});
</script>
こちらの方法は、HTMLとJavaScriptを分離しやすく、メンテナンス性や拡張性に優れています。
addEventListenerを使うことで、イベントハンドラを柔軟に追加したり、削除したりすることも簡単です。
「mouseup」と他のマウスイベントとの違い
mousedownとの違い
- mousedown
- ユーザーがマウスボタンを押し下げた直後
- mouseup
- 押されたボタンが離された直後
これらを併用することで、ドラッグ操作の開始・終了を検知したり、描画操作(お絵かきツールなど)で線を引き始めるタイミングと終わるタイミングを捉えたりできます。
clickとの違い
- click
- 通常、
mousedown→mouseupが同じ要素で発生した場合に呼び出される - mouseup
- 要素上でボタンを離した瞬間(要素上からmousedragして他の要素上でボタンを離すと呼び出されないこともある)
clickイベントは、実際にユーザーが「クリック」したことを示します。ですが、ユーザーがボタンを押し、ドラッグした後に別の場所でボタンを離した場合、clickは発生しません。一方、mouseupは要素上でボタンを離したら必ず発生します(ただし、要素上にマウスが乗っている必要があります)。
mousemoveとの違い
- mousemove
- マウスカーソルが要素上で動いている間、継続的に呼び出される
- mouseup
- 押下していたボタンが上がった瞬間に1回だけ呼び出される
ドラッグアンドドロップの実装では、通常 mousedown でドラッグを開始し、mousemoveで移動を検知し、mouseupでドラッグの終了処理を行う、という手法が一般的です。
基本的なコード例
シンプルな例
以下は、ユーザーがボタンをクリックして離した瞬間にメッセージを表示する例です。
HTML
<button id="myButton" type="button">クリックして離す</button>
<p id="mouseup-result" role="status" aria-live="polite" aria-atomic="true"></p>
<script>
const button = document.getElementById("myButton");
button.addEventListener("mouseup", function(event) {
// イベントオブジェクトでボタンの種類を確認(0:左, 1:中, 2:右)
const buttonType = event.button;
let message = "";
switch(buttonType) {
case 0:
message = "左ボタンが離されました。";
break;
case 1:
message = "中ボタン(ホイール)が離されました。";
break;
case 2:
message = "右ボタンが離されました。";
break;
default:
message = "不明なボタンが離されました。";
}
console.log(message);
document.getElementById("mouseup-result").textContent = message;
});
</script>
上記の例では、event.buttonプロパティを使ってどのマウスボタンが離されたか判断し、メッセージを表示しています。
応用例と実践的な活用シーン
ドラッグアンドドロップ操作
「ドラッグアンドドロップ」は、以下のような流れで実装されることが多いです。
mousedownでドラッグ開始判定・初期設定mousemoveで要素の位置を更新mouseupでドラッグの終了処理
HTML
<div id="draggable">ドラッグできます</div>
<script>
const box = document.getElementById("draggable");
let isDragging = false;
let offsetX, offsetY;
box.addEventListener("mousedown", (event) => {
isDragging = true;
// 要素の左上とマウスの座標の差分を保存
offsetX = event.clientX - box.offsetLeft;
offsetY = event.clientY - box.offsetTop;
});
document.addEventListener("mousemove", (event) => {
if (isDragging) {
box.style.left = (event.clientX - offsetX) + "px";
box.style.top = (event.clientY - offsetY) + "px";
}
});
document.addEventListener("mouseup", (event) => {
if (isDragging) {
isDragging = false;
console.log("ドラッグ終了");
}
});
</script>
mouseupをドキュメント全体(document)に登録することで、マウスが要素外へ移動してもマウスボタンが離されたタイミングを逃さずに取得できます。isDraggingフラグを使って、ドラッグ中かどうかを判定し、ドラッグ終了でフラグを解除します。
お絵かきツール
canvas要素を用いたシンプルな「お絵かき」機能の例です。
mousedown:描画開始(描画フラグをtrueに)mousemove:描画フラグがtrueの間だけ線を引くmouseup:描画終了(描画フラグをfalseに)
ここでも、mouseupが描画終了タイミングとして重要です。
イベントオブジェクトの詳細
mouseupイベントで受け取れるイベントオブジェクト(MouseEvent)には、多くの情報が含まれています。
- event.button
- どのマウスボタンか(0:左, 1:中, 2:右)
- event.clientX, event.clientY
- ビューポート(画面)上でのマウス座標
- event.screenX, event.screenY
- ディスプレイ全体に対するマウス座標
- event.altKey, event.ctrlKey, event.shiftKey, event.metaKey
- 修飾キーの状態
- event.target
- イベントが発生した要素(もしくはバブリング経路上の要素)
- event.type
- イベントの種類("mouseup"など)
また、バブリングやキャプチャリングに関する制御も可能です。詳しくは次の「イベント伝播と高度な話題」で解説します。
イベント伝播と高度な話題
キャプチャリングとバブリング
JavaScriptのイベント伝播には、キャプチャリングフェーズとバブリングフェーズがあります。
- キャプチャリングフェーズ
- 最上位のルート(
document)から目的の要素に向かってイベントが伝播する - ターゲットフェーズ
- 実際にイベントが発生した要素が処理を受け取る
- バブリングフェーズ
- イベントが親要素へ向かって伝播する
addEventListenerの第3引数またはオプションでcapture: trueを指定すると、キャプチャリングフェーズでイベントを受け取ることができます。通常はバブリングフェーズで受け取ります。
JavaScript
element.addEventListener("mouseup", handler, { capture: true });
こうすると、要素の子孫より先にイベントを受け取れるため、ネストした要素全体の制御が必要なケースやイベントの取り消しが必要な場合などで役立ちます。
イベントの停止
- event.stopPropagation()
- バブリングまたはキャプチャリングを途中で停止する
- event.preventDefault()
- デフォルト動作(右クリックメニューの表示等)をキャンセルする
例:右クリックメニューを独自のコンテキストメニューに差し替えたい場合、contextmenuイベントやmouseupイベントでevent.preventDefault()を呼び出すことで、ブラウザの標準動作を抑止してカスタムメニューを表示できます。
HTML
<div id="customArea">
右クリックしてみてください
</div>
<script>
const area = document.getElementById("customArea");
area.addEventListener("mouseup", (event) => {
// 右クリック(event.button === 2)のときカスタムメニュー表示
if (event.button === 2) {
event.preventDefault(); // ブラウザのコンテキストメニューを表示しない
alert("カスタムコンテキストメニューを表示します(ダイアログで代用)");
}
});
area.addEventListener("contextmenu", (event) => {
event.preventDefault(); // こちらでも追加の防止処理を
});
</script>
ベストプラクティスと注意点
イベントの付けすぎに注意
たとえば、複数の要素に対して同じmouseup処理を行いたい場合、一括で親要素またはdocumentに付けてイベントデリゲーションを使う方法があります。多数の要素それぞれにaddEventListenerを行うと、パフォーマンスに影響する場合もあります。
JavaScript
document.body.addEventListener("mouseup", (event) => {
if (event.target.matches(".myClass")) {
// クラスが myClass の要素がmouseupされた場合にのみ処理
console.log("クラスmyClassの要素からのmouseup");
}
});
タッチデバイスの考慮
スマホやタブレットなど、タッチパネルではマウス操作そのものが存在しないことがあります。タッチイベント(touchstart, touchend, touchmove)と組み合わせて実装するか、ポインターイベント(pointerdown, pointerup, pointermove)で統合的に処理するのが望ましいです。
ドキュメント全体へのリスナー
ドラッグやお絵かきなど、マウスが要素の外へ移動してしまう可能性がある場合は、mouseupをドキュメント全体(document)またはウィンドウ(window)に対して登録すると、イベントを逃さず取得できます。ただし、大量のイベントを捌くことになるので、可能な範囲で最適化するとよいでしょう。
パフォーマンスチューニング
- ロジックを最適化
- mouseupで重い処理をしない(他のタイミングに処理を分割する)
- requestAnimationFrameの活用
- アニメーションを伴う処理は、mousemoveやmouseupの都度行うよりも、requestAnimationFrameのコールバック内でまとめて処理するとスムーズになります。
デバッグやトラブルシューティングのポイント
- イベントが発火しない
-
- そもそも要素の上でボタンが離されていないか
event.stopPropagation()やevent.preventDefault()をどこかで呼び出していないか- イベントがバブリングフェーズで取得できるかどうか(キャプチャリングを利用していないか)
- イベントの順序が予期と違う
-
mousedown→mouseup→clickの順序を理解しよう- 他のイベントが割り込んでいないか
- ドラッグしている最中に動作が途切れる
-
- マウスが要素外へ移動したときに
mousemoveやmouseupを受け取れるよう、documentにリスナーを付与する
- マウスが要素外へ移動したときに
- IEや古いブラウザ対応
-
- 古いブラウザでは
addEventListenerやremoveEventListenerがサポートされていないケースがある(attachEvent,detachEventが必要) - ただし近年はサポート範囲が大幅に進んでいるため、IE専用対応が必要かどうか検討する
- 古いブラウザでは
まとめ
- 「mouseup」イベントは、マウスボタンを離した瞬間に発生するイベント。
- マウスのクリック、ドラッグ、右クリックなどの挙動を詳細に制御する場合に非常に有用。
- 基本的な流れ:
mousedown(開始) →mousemove(移動) →mouseup(終了)、あるいはclick。 event.buttonや座標プロパティ、修飾キーなどを使用すると高度な制御が可能。- ドラッグアンドドロップやお絵かきツール、独自コンテキストメニューなど、幅広い応用範囲がある。
- キャプチャリングやバブリングなどイベント伝播のメカニズムを理解することで、複雑なUIの実装にも対応できる。
- タッチデバイスやポインターイベントへの対応も必要な場合がある。
JavaScriptにおけるマウスイベントはUI操作の基盤となるため、「mouseup」以外にも「mousedown」「click」「mousemove」「mouseenter」「mouseleave」「contextmenu」などと合わせて理解することが大切です。応用範囲は広いので、まずは基本的なサンプルを動かしてみて、徐々に複雑なケースへとステップアップしていきましょう。