最近公司项目需要, 要实现类似游戏里面物品栏之间的拖放功能,网上关于拖拽的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);
	}
}

DragDrop 下载