/// 脚本引用 /// /// /// 功能模块:启明js拖拽类 /// 作者:黄顺权 /// 编码日期:2014年09月23日 /// (function ($) { /// /// jQuery对象的扩展方法 /// $.fn.extend({ /// 获得对象的绝对布局 getLayout: function () { var pos = this.css("position") == "static" ? this.offset() : this.position(); var w = this.width(); var h = this.height() return { left: pos.left, top: pos.top, right: pos.left + w, bottom: pos.top + h, width: w, height: h }; }, /// 获得对象的偏移布局 getOffsetLayout: function () { var pos = this.offset(); var w = this.width(); var h = this.height() return { left: pos.left, top: pos.top, right: pos.left + w, bottom: pos.top + h, width: w, height: h }; } }); /// 定义$.qm命名空间 if (typeof ($.qm) != "object") $.qm = {}; /// /// 定义拖放匿名类,最后将该类绑定到$.qm命名空间下 /// (function () { /// 拖拽状态标志 var _isDragging = false; /// 拖放对象 var _dropObjects = []; /// 默认拖拽配置 var _defaultDragOptions = { container: null, handle: null, proxy: null, revert: false, delay: 0, cursor: 'pointer', onStartDrag: function (e) { }, onDrag: function (e) { }, onStopDrag: function (e) { }, onClick: function (e) { } }; /// 默认拖放配置 var _defaultDropOptions = { onDropOver: function (e) { }, onDrop: function (e, source, target) { } }; /// 单击事件代理函数 var onclickHook = function (e) { if (_isDragging) return; var dragInfo = $.data(this, "qm_drag"); if (dragInfo.onclick instanceof Function) dragInfo.onclick.call(this, e); }; /// 双击事件代理函数 var ondblclickHook = function (e) { if (_isDragging) return; var dragInfo = $.data(this, "qm_drag"); if (dragInfo.ondblclick instanceof Function) dragInfo.ondblclick.call(this, e); }; /// 获得鼠标位置 var getMousePos = function (e) { //return { x: e.originalEvent.x || e.originalEvent.layerX || 0, y: e.originalEvent.y || e.originalEvent.layerY || 0 }; return { x: e.pageX, y: e.pageY }; }; /// 判断坐标点是否在矩形内 var ptInRect = function (pt, rect) { return pt.x > rect.left && pt.x < rect.right && pt.y > rect.top && pt.y < rect.bottom; }; /// 判断第一个矩形是否在第二个矩形内 var rectInRect = function (rect1, rect2) { return rect1.left > rect2.left && rect1.top > rect2.top && rect1.right < rect2.right && rect1.bottom < rect2.bottom; }; /// 鼠标按下事件检测函数 var mouseDownCheck = function (e) { //获得鼠标事件参数 var eventArgs = $.extend(true, {}, e); //获得运行时参数 var dragInfo = $.data(e.data.srcElement, "qm_drag"); var opts = dragInfo.options; var source = this; //判断是否需要延时触发拖拽事件 if (opts.delay > 0) { //延时触发 this.setCapture(); var theElementLayout = $(this).getLayout(); var timerID = setTimeout(function () { _isDragging = true; $(document).unbind(".dragCheck"); mouseDownHandler.call(source, eventArgs); }, opts.delay); $(document).bind("mousemove.dragCheck", { srcElement: this }, function (e) { var mousePos = getMousePos(e); eventArgs = $.extend(true, {}, e); //获得鼠标事件参数 if (!ptInRect(mousePos, theElementLayout)) { clearTimeout(timerID); e.data.srcElement.releaseCapture(); $(document).unbind(".dragCheck"); } }); $(document).bind("mouseup.dragCheck", { srcElement: this }, function (e) { clearTimeout(timerID); e.data.srcElement.releaseCapture(); $(document).unbind(".dragCheck"); }); } else {//立即触发拖拽事件 _isDragging = true; mouseDownHandler.call(source, eventArgs); } }; /// 鼠标按下事件处理函数 var mouseDownHandler = function (e) { //获得运行时参数 var dragInfo = $.data(this, "qm_drag"); var source = dragInfo.source; var opts = dragInfo.options; //保存当前鼠标位置 dragInfo.mousePos = getMousePos(e); //获得被拖拽对象的当前布局 source.layout = source.getLayout(); //获得容器的布局 if (opts.container != null) { var container = $(opts.container); dragInfo.containerLayout = container.getLayout(); } //获得实际被拖拽的代理对象 if (opts.proxy == 'clone') { dragInfo.proxy = source.clone().insertAfter(this); } else { dragInfo.proxy = source; } var proxy = dragInfo.proxy; //获得拖拽对象的定位和zIndex source._position = source.css("position"); source._zIndex = source.css("z-index"); //设置被拖拽对象的起始位置 proxy.css({ position: "absolute", left: source.layout.left + 5 + "px", top: source.layout.top + 5 + "px" }); //设置新的zIndex proxy.css("z-index", 1002); //获得被拖拽对象的当前位置(移移5像素,以便增加视觉效果) proxy.currentPos = { left: source.layout.left + 5, top: source.layout.top + 5 }; //设置鼠标抓取能力 document.documentElement.setCapture(); //绑定鼠标移动和抬起事件 $(document).bind('mousemove.dragging', { srcElement: this }, mouseMoveHandler); $(document).bind('mouseup.dragging', { srcElement: this }, mouseUpHandler); //触发调用者的拖拽开始事件 //opts.onStartDrag.call(this, e); opts.onStartDrag.call(proxy[0], e); }; /// 鼠标移动事件处理 var mouseMoveHandler = function (e) { //获得运行时参数 var dragInfo = $.data(e.data.srcElement, "qm_drag"); var source = dragInfo.source; var proxy = dragInfo.proxy; var opts = dragInfo.options; //获得当前鼠标位置 var mousePos = getMousePos(e); //计算鼠标移动距离 var distance = { x: mousePos.x - dragInfo.mousePos.x, y: mousePos.y - dragInfo.mousePos.y }; //保存当前鼠标位置 dragInfo.mousePos = mousePos; //获得被拖拽对象移到的位置 proxy.currentPos.left += distance.x; proxy.currentPos.top += distance.y; //移动被拖拽对象 if (opts.container != null) { //获得被拖拽对象的新的布局 var rect = { left: proxy.currentPos.left, top: proxy.currentPos.top, right: proxy.currentPos.left + source.layout.width, bottom: proxy.currentPos.top + source.layout.height }; var containerLayout = dragInfo.containerLayout; if (rectInRect(rect, containerLayout)) { //如果被拖拽对象在容器内部 //设置被拖拽对象的水平和垂直坐标 proxy.css({ left: proxy.currentPos.left + "px", top: proxy.currentPos.top + "px" }); } else if (rect.left > containerLayout.left && rect.right < containerLayout.right) { //如果被拖拽象的水平坐标在容器内部 //设置被拖拽对象的水平坐标 proxy.css({ left: proxy.currentPos.left + "px" }); } else if (rect.top > containerLayout.top && rect.bottom < containerLayout.bottom) { //如果被拖拽象的垂直坐标在容器内部 //设置被拖拽对象的垂直坐标 proxy.css({ top: proxy.currentPos.top + "px" }); } } else { proxy.css({ left: proxy.currentPos.left + "px", top: proxy.currentPos.top + "px" }); } //触发调用者的拖拽事件 opts.onDrag.call(source[0], e); //触发拖放对象的onDropOver事件 var eventArgs = $.extend(true, {}, e); for (var i = 0; i < _dropObjects.length; i++) { var objDrop = $(_dropObjects[i]); var layout = objDrop.getLayout(); if (ptInRect(mousePos, layout)) { var options = $.data(_dropObjects[i], "qm_drop").options; options.onDropOver.call(_dropObjects[i], eventArgs); } } }; /// 鼠标抬起事件处理 var mouseUpHandler = function (e) { //获得运行时参数 var dragInfo = $.data(e.data.srcElement, "qm_drag"); var source = dragInfo.source; var proxy = dragInfo.proxy; var opts = dragInfo.options; //获得当前鼠标位置 var mousePos = getMousePos(e); //取消鼠标抓取 document.documentElement.releaseCapture(); //取消事件绑定 $(document).unbind('.dragging'); //复制事件参数 var eventArgs = $.extend(true, {}, e); //设置拖拽标志结束 _isDragging = false; //触发调用者的拖拽结束事件 opts.onStopDrag.call(source[0], e); //结束拖拽 var stopDrag = function () { //处理实际被拖拽的对象 if (opts.proxy == 'clone') { proxy.remove(); //删除代理 } else { //恢复原来的定位方式和zIndex source.css("position", source._position); source.css("z-index", source._zIndex); } } //触发拖放对象的onDrop事件 for (var i = 0; i < _dropObjects.length; i++) { var theElement = _dropObjects[i]; if (theElement == e.data.srcElement) continue; var objDrop = $(theElement); var layout = objDrop.getLayout(); if (ptInRect(mousePos, layout)) { var options = $.data(theElement, "qm_drop").options; if (options.onDrop.call(e.data.srcElement, eventArgs, e.data.srcElement, theElement) == false) { stopDrag(); return; } } } if (opts.revert) { //如果恢复到拖拽前的位置 var layout = source.getLayout(); proxy.animate({ left: layout.left + "px", top: layout.top + "px" }, stopDrag); } else { stopDrag(); } }; /// 拖拽方法 this.drag = function (dragObjects, options) { //处理容器布局,以防拖拽超出了容器的范围 if (options instanceof Object && options.container) { var container = $(options.container); $(window).bind("resize", { container: container }, function (e) { e.data.container[0].layout = e.data.container.getLayout(); }); } //遍历每个对象注册鼠标事件 $(dragObjects).each(function () { var opts; //获得运行时配置(以便fn.qm.drag可以多次调用) var dragInfo = $.data(this, "qm_drag"); if (!(dragInfo instanceof Object)) { opts = $.extend({}, _defaultDragOptions, options || {}); } else { opts = $.extend(dragInfo.options, options); } //保存运行时配置 var objDrag = $(this); dragInfo = { options: opts, source: objDrag, //要拖拽的对象 handle: opts.handle ? $(opts.handle) : objDrag, //拖拽把手 onclick: this.onclick, ondblclick: this.ondblclick }; this.onclick = onclickHook; this.ondblclick = ondblclickHook; $.data(this, "qm_drag", dragInfo); //设置被拖拽对象的鼠标形状 objDrag.css("cursor", opts.cursor); //检查鼠标按下事件 $(dragInfo.handle).bind("mousedown", { srcElement: this }, mouseDownCheck); }); }; /// 拖放方法 this.drop = function (dropObjects, options) { dropObjects = $(dropObjects); //遍历每个对象注册拖放事件 $(dropObjects).each(function () { var opts; //保存拖放对象到全局数组中 _dropObjects.push(this); //获得运行时配置 var dropInfo = $.data(this, "qm_drop"); if (!(dropInfo instanceof Object)) { opts = $.extend({}, _defaultDropOptions, options || {}); } else { opts = $.extend(dropInfo.options, options); } //保存运行时配置 var dropObj = $(this); dropInfo = { options: opts, source: dropObj //要拖放的对象 }; $.data(this, "qm_drop", dropInfo); }); }; }).call($.qm); })(jQuery);