2008年6月30日月曜日

ライブラリを使わないでドラッグ&ドロップするサル

jQueryでドラッグ&ドロップする方法を考えてみた。Draggablesというライブラリを使えば簡単にできるようですが↓
http://allabout.co.jp/internet/javascript/closeup/CU20080115A/
あんまり簡単過ぎて面白くないので自分で書いてみることにした。

マウスドラッグというイベントは無いので、既存のイベントでどうにかするしかない。ドラッグする要素にposition: absoluteを指定して、mousedown→mousemove→mouseupという流れで順にハンドリングする。という感じでとにかく書いてみた。

<div class="hoge" style="
width: 100px;
height: 100px;
background-color: #ffff00;
position: absolute;
">hoge</div>

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">

$("div.hoge").mousedown(function(event){
$(this).mousemove(function(event){
$(this).css("left",event.pageX).css("top",event.pageY);
});
$(this).mouseup(function(event){
$(this).unbind("mousemove");
});
});

</script>


動きました。IEでも問題なし。よしよしと思ったけどドラッグ開始直後にブロック要素がぴょこんと右下に飛ぶ。マウスカーソルに合わせて要素のポジションを書き換えているので、要素の左上隅の座標とmousedownイベント発生時の座標の差だけ飛ぶんだな。

そして下記が修正版。イベント発生時にイベントの発生した座標と要素の座標の差を求めて、mousemoveイベントの座標から引くというロジック。IEではleftとtopの指定がないと$(elm).css("left")で値を取得できなかったのでstyle属性に追加。

<div class="hoge" style="
width: 100px;
height: 100px;
background-color: #ffff00;
position: absolute;
left: 10px;
top: 10px;

">hoge</div>

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">

$("div.hoge").mousedown(function(event){
eX = event.pageX - $(this).css("left").replace(/px/,"");
eY = event.pageY - $(this).css("top").replace(/px/,"");

$(this).mousemove(function(event){
$(this).css("left",event.pageX - eX).css("top",event.pageY - eY);
});
$(this).mouseup(function(event){
$(this).unbind("mousemove");
});
});

</script>


よしよしと思ったらまだ問題があった。ドラッグ中にマウスを高速に動かすと要素がついてこない。要素の上にマウスカーソルを合わせるとまた動くようになる。イベントを$(this).mousemove()とセットしているのでthisの上でのmouseumoveじゃないとイベントが発生しないんだな。

ということでまた修正。mousemoveとmouseupは$(document)にセットする。セットした関数の中で$(this)が使えなくなったのでドラッグ中の要素には識別子としてdragをクラス属性に追加する。今度こそばっちりだ。

$("div.hoge").mousedown(function(event){
$(this).addClass("drag");
eX = event.pageX - $(this).css("left").replace(/px/,"");
eY = event.pageY - $(this).css("top").replace(/px/,"");
$(document).mousemove(function(event){
$("div.drag").css("left",event.pageX - eX).css("top",event.pageY - eY);
});
$(document).mouseup(function(event){
$("div.drag").unbind("mousemove");
$("div.drag").removeClass("drag");
});
});

0 件のコメント: