現在受けてるNuxt.jsの授業の課題のひとつで『jQuery UIを使わずにドラッグドロップを実装する』というのがあって、一見難しい様でJavaScriptをしっかり使いこなせていればなんて事なく、普段使わないflagの使い方を知るすごくいい課題だったので、復習の為にまとめようと思いました。
ドラッグドロップのイベントを分解すると以下の3つになります。
① mousedown
要素をクリック
② mousemove
クリックしたままマウスを動かす=ドラッグ
③ mouseup
クリック解除してドラッグ終了
まずは必要なグローバル変数などを用意。
movingはフラグです。
var elements = document.getElementById("red");
var x;
var y;
var moving = false;
elements.addEventListener("mousedown", function (e) {
moving = true;
x = e.pageX - this.offsetLeft;
y = e.pageY - this.offsetTop;
}, false);
① mousedown
要素をクリックした時、movingをtrueにします。
これ自体には意味ありません。フラグの名の通り、旗で、目印です。後で役に立ちます。
そして、次の行で不思議な計算をします。これは百聞は一見にしかずで目でみた方がわかりやすいと思い、図にしました。
なぜこの部分の値を求めておくのかは次のmousemoveでわかります。
window.addEventListener("mousemove", function (e) {
if (moving == false) return
elements.style.top = e.pageY - y + "px";
elements.style.left = e.pageX - x + "px";
}, false);
② mousemove
マウスを動かしている時のイベントを検出するのですが、ここで最初に設定したフラグが役に立ちます。フラグがfalseの時(要素をクリックしてない時)はその下の処理は実行しません。こうしておかないとマウスの動きを常に検出してしまいます。
そして、マウスを動かしてカーソルの座標(pageX, Y)をそのままCSSに入れてもドラッグドロップは成立するのですが、そうするとドラッグし終わった時に要素の左上が矢印の位置にずれるのです。これはCSSのtop, left値が要素の左上のx, y座標だからです。
これも百聞は一見にしかずだと思うので、別で用意しました。
こちらをどうぞ
もう一点ここでの注意点として、dom要素のelementsに対してではなく、windowにaddEventListenerを指定してます。これはdom要素のelementsに指定するとマウスの動きについてこれずに素早くドラッグすると要素が置いていかれてしまうバグが発生してしまうのを防ぐためです。
これがそのサンプルです
elements.addEventListener("mouseup", function () {
moving = false;
}, false);
③ mouseup
最後にマウスのボタンを離した時にドロップになります。ここでの処理はフラグをfalseに戻すだけ、これでmousemoveで行われてる計算は行われなくなり、要素の動きも止まります。
実際の開発の現場ではjQueryUI使うと思うけど、あえて使わずに書くというこの経験がコード力をあげていくと思いました。