最近公司项目需要, 要实现类似游戏里面物品栏之间的拖放功能,网上关于拖拽的JS大部分都是只适合做单个元素的拖放(drag and drop) 找了很就也没找到满足需求的. 只好自己写一个了. BTW:鸡肯肉(jquery)UI组件倒是有drag drop 但是用起来太复杂 而且总觉得卡卡的 代码也很多 还要 JQUI core的支持.所以还是自己动手 丰衣足食.
原理:
drag功能好做 就不多说了
drop,一个drop对象的时候也好做 就是鼠标弹起时判断是否在drop对象内部 是的话就drop下来
而难点在于多个drag对象 且 多个可drop的对象的时候就麻烦了 , 因为首先要知道拖的是哪个 其次还要知道放下的时候是在哪个drop对象里. 这里我用的方法是循环 循环判断 放下的时候是在哪个drop元素上.
本人语文不好 表达可能不太清楚. 先看DEMO:
查看DEMO
代码:
//拖放插件DragDrop
$.fn.Drag=function (options) {
//document.body.onselectstart=function(){return false;}
var defaults={
limit : window,//是否限制拖放范围
drop:false,//是否可drop
noDrop:false,//是否可drop
handle:false,//是否可drop
finish:function () {}//拖拽完成后回调函数
}
var options=$.extend(defaults,options);
this.X=0;//初始位置
this.Y=0;
this.dx=0;//位置差值
this.dy=0;
var This=this;
var ThisO=$(this);//被拖目标
var newElm;//放下目标(单个)
ThisO.unbind('mousedown');//囧 Orz..
if (options.drop) {
var ThatO=$(options.drop);//可放下位置(多个)
ThisO.find('div').css({cursor:'move'});
var tempBox=$('<div id="tempBox" class="grid"></div>');
}else {
if (options.handle) {
ThisO.find(options.handle).css({cursor:'move'});
}else {
ThisO.css({cursor:'move'});
}
}
//拖动开始
this.dragStart=function (e) {
var cX=e.pageX;
var cY=e.pageY;
if (options.drop) {
ThisO=$(this);
if (ThisO.find('div').length!=1) {return}//如果没有拖动对象就返回
This.X=ThisO.find('div').offset().left;
This.Y=ThisO.find('div').offset().top;
tempBox.html(ThisO.html());
ThisO.html('');
$('body').append(tempBox);
tempBox.css('left',This.X);
tempBox.css('top',This.Y);
}else {
This.X=ThisO.offset().left;
This.Y=ThisO.offset().top;
ThisO.css({margin:0})
}
This.dx=cX-This.X;
This.dy=cY-This.Y;
if (!options.drop) {
ThisO.css({position:'absolute',left:This.X,top:This.Y});
}
$(document).mousemove(This.dragMove);
$(document).mouseup(This.dragStop);
if ($.browser.msie) {ThisO[0].setCapture();};
return true;
}
//拖动中
this.dragMove=function (e) {
var cX=e.pageX;
var cY=e.pageY;
if (options.limit) {//限制拖动范围
//容器的尺寸
var L=$(options.limit)[0].offsetLeft ? $(options.limit).offset().left : 0;
var T=$(options.limit)[0].offsetTop ? $(options.limit).offset().top : 0;
var R=L+$(options.limit).width();
var B=T+$(options.limit).height();
//获取拖动范围
var iLeft=cX-This.dx, iTop=cY-This.dy;
//获取超出长度
var iRight=iLeft+parseInt(ThisO.outerWidth())-R, iBottom=iTop+parseInt(ThisO.outerHeight())-B;
//先设置右下, 再设置左上
if(iRight > 0) iLeft -= iRight;
if(iBottom > 0) iTop -= iBottom;
if(L > iLeft) iLeft = L;
if(T > iTop) iTop = T;
if (options.drop) {
tempBox.css({left:iLeft,top:iTop})
}else {
ThisO.css({left : iLeft,top : iTop})
}
}else {
//不限制范围
if (options.drop) {
tempBox.css({left:cX-This.dx,top:cY-This.dy})
}else {
ThisO.css({left:cX-This.dx,top:cY-This.dy});
}
};
return false;
}
//拖动结束
this.dragStop=function (e) {
if (options.drop) {
var flag=false;
var cX=e.pageX;
var cY=e.pageY;
var oLf=ThisO.offset().left;
var oRt=oLf+ThisO.width();
var oTp=ThisO.offset().top;
var oBt=oTp+ThisO.height();
if (!(cX>oLf && cX<oRt && cY>oTp && cY<oBt)) {//如果不是在原位
for (var i=0; i<ThatO.length; i++) {
var XL=$(ThatO[i]).offset().left+parseInt($(ThatO[i]).css('paddingLeft'));
var XR=XL+$(ThatO[i]).width();
var YL=$(ThatO[i]).offset().top+parseInt($(ThatO[i]).css('paddingTop'));
var YR=YL+$(ThatO[i]).height();
if (XL<cX && cX<XR && YL<cY && cY<YR) {//找到拖放目标 (如果有X个格子位置重叠 将会找到X个 newElm的值是最后一个,这是个待解决问题)
newElm=$(ThatO[i]);
flag=true;
}
}
if (flag) {//交换位置
var temp=newElm.html();
newElm.html(tempBox.html());
ThisO.html(temp);
tempBox.remove();
}
}
if (!flag) {//如果找不到拖放位置,归回原位
tempBox.css('left',This.X);
tempBox.css('top',This.Y);
ThisO.html(tempBox.html());
tempBox.remove();
}
}
$(document).unbind('mousemove');
$(document).unbind('mouseup');
options.finish(e,ThisO,newElm);//回调
if ($.browser.msie) {ThisO[0].releaseCapture();};
return false;
}
//绑定拖动
if (options.handle) {
ThisO.find(options.handle).mousedown(This.dragStart);
}else {
ThisO.mousedown(This.dragStart);
}
}
1 Comment
老費
樓主您好,小弟在寫網頁的時候,找到您的範例,正好符合需求,在此先謝過。因小弟是jquery 的初學者,想請教一下,如果我想在拖動後對資料庫做讀寫的動作,應該將程式碼放在哪個位置?
網頁環境:php + mysql