ReactとBulmaの組み合わせで、マウスドラッグ可能なモーダルダイアログを実装する方法について紹介します。
スポンサーリンク
前提
対象のReactプロジェクトに対して、Bulmaのセットアップが出来ているものとします。
まだセットアップできていない場合は、以下のコマンドでインストールすれば使えます。
npm install bulma
もしくは、CDN経由で使う場合は、 public/index.html
に以下のコードを追加します。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
ドラッグ可能なダイアログの実装
本題のドラッグ可能なモーダルダイアログの実装をします。詳細な処理内容はコードの中のコメントを見て頂ければと思います。
import React, { useEffect, useRef, useState } from 'react'
function DraggableDialog() {
//ドラッグ中かを判定するフラグ
const [isDrag, setIsDrag] = useState(false)
//ドラッグ情報を保持するステート
const [state, setState] = useState({
sx: 0, //ドラッグ開始時の「pageX」
sy: 0, //ドラッグ開始時の「pageY」
mx: 0, //ドラッグ時のX方向の移動量を保持
my: 0, //ドラッグ時のY方向の移動量を保持
tx: 0, //対象要素の相対位置(X)
ty: 0, //対象要素の相対位置(Y)
})
//Mouse Down
const handleMouseDown = (e) => {
//マウスドラッグ開始位置の初期化
setState(old => {
return {
...old,
sx: e.pageX,
sy: e.pageY,
mx: 0,
my: 0,
}
})
//ドラッグ中のフラグをON
setIsDrag(true)
}
useEffect(() => {
//ドラッグ中の場合はウィンドウのマウスイベントを監視
if (isDrag) {
window.addEventListener("mousemove", handleMouseMove)
window.addEventListener("mouseup", handleMouseUp)
}
return () => {
window.removeEventListener("mousemove", handleMouseMove)
window.removeEventListener("mouseup", handleMouseUp)
}
}, [isDrag])
//ウィンドウのマウス移動イベント
const handleMouseMove = (e) => {
setState(old => {
return {
...old,
mx: e.pageX - old.sx,
my: e.pageY - old.sy,
}
})
e.preventDefault()
}
/**
* ヘッダのマウスダウン
* @param {MouseEvent} e
*/
const handleMouseUp = (e) => {
//if (!isDrag) return
setState(old => {
return {
...old,
tx: old.tx + old.mx,
ty: old.ty + old.my,
mx: 0,
my: 0,
}
})
setIsDrag(false)
}
return (
<div className="modal is-active">
<div className="modal-background"></div>
<div
className="modal-card"
style={{
transform: `translate(${state.tx + state.mx}px, ${state.ty + state.my}px)`
}}
>
<header
className="modal-card-head"
onMouseDown={handleMouseDown}
>
<p className="modal-card-title">Modal title</p>
<button className="delete" aria-label="close"></button>
</header>
<section className="modal-card-body">
コンテンツ
</section>
<footer className="modal-card-foot">
<button className="button is-success">OK</button>
<button className="button">Cancel</button>
</footer>
</div>
</div>
)
}
export default DraggableDialog
このコードでは、useStateフックを使用して、ドラッグの開始位置、移動距離、ドラッグ中かどうかなどの情報を保持するstate変数を宣言します。また、今回はダイアログのヘッダー部分をドラッグすると移動するようにしています。
0 件のコメント:
コメントを投稿