项目中经常会有拖拽功能。
自己写的一个用于拖拽的库。
先看一下效果
代码如下(dragUtil.js):
/** * 拖拽工具 */ function DragUtil(view, mouseDownCallback, mouseMoveCallback, mouseUpCallback, onlyView, prevent, stop) { this.map = {}; this.view = view; this.onlyView = onlyView; // 只响应view的鼠标事件,忽略children this.prevent = prevent; // 是否执行preventDefault this.stop = stop; // 是否执行stopPropagation this.mouseDownCallback = mouseDownCallback; this.mouseMoveCallback = mouseMoveCallback; this.mouseUpCallback = mouseUpCallback; this.mouseDownHandler = this._mouseDownHandler.bind(this); this.mouseMoveHandler = this._mouseMoveHandler.bind(this); this.mouseUpHandler = this._mouseUpHandler.bind(this); this.touchStartHandler = this._touchStartHandler.bind(this); this.touchMoveHandler = this._touchMoveHandler.bind(this); this.touchEndHandler = this._touchEndHandler.bind(this); this.view.addEventListener("mousedown", this.mouseDownHandler); this.view.addEventListener("touchstart", this.touchStartHandler); this.onDown = function(){}; this.onMove = function(){}; this.onUp = function(){}; } DragUtil.prototype.destroy = function() { this.view.removeEventListener("mousedown", this.mouseDownHandler); this.view.removeEventListener("touchstart", this.touchStartHandler); this.removeTouchListeners(); this.view = null; this.mouseDownCallback = null; this.mouseMoveCallback = null; this.mouseUpCallback = null; this.map = null; } DragUtil.prototype.onMouseDownCallback = function(id, x, y, e) { this.map[id] = {x: x, y: y}; if (this.mouseDownCallback) { this.mouseDownCallback(id, x, y, e); } this.onDown(id, x, y, e); } DragUtil.prototype.onMouseMoveCallback = function(id, x, y, e) { var o = this.map[id]; if (this.mouseMoveCallback) { this.mouseMoveCallback(id, x, y, x - o.x, y - o.y, e); } this.onMove(id, x, y, x - o.x, y - o.y, e); o.x = x; o.y = y; } DragUtil.prototype.onMouseUpCallback = function(id, x, y, e) { if (this.mouseUpCallback) { this.mouseUpCallback(id, x, y, e); } delete this.map[id]; this.onUp(id, x, y, e); } //-------------------drag--------------------- DragUtil.prototype._mouseDownHandler = function(e) { // console.log("mouse down", this, e); if(this.onlyView && e.target != this.view) { return; } this.onMouseDownCallback(-1, e.clientX, e.clientY, e); document.addEventListener("mousemove", this.mouseMoveHandler, {passive: false}); document.addEventListener("mouseup", this.mouseUpHandler); document.addEventListener("mouseleave", this.mouseUpHandler); } DragUtil.prototype._mouseMoveHandler = function(e) { if(this.prevent) { e.preventDefault(); } if(this.stop) { e.stopPropagation(); } this.onMouseMoveCallback(-1, e.clientX, e.clientY, e); } DragUtil.prototype._mouseUpHandler = function(e) { this.onMouseUpCallback(-1, e.clientX, e.clientY, e); this.removeMouseListeners(); } DragUtil.prototype.removeMouseListeners = function() { document.removeEventListener("mousemove", this.mouseMoveHandler); document.removeEventListener("mouseup", this.mouseUpHandler); document.removeEventListener("mouseleave", this.mouseUpHandler); } DragUtil.prototype.forEachTouch = function(e, callback) { for(var i = 0; i < e.changedTouches.length; i++) { callback(e.changedTouches[i]); } } DragUtil.prototype._touchStartHandler = function(e) { // console.log("touch start", this, e); this.forEachTouch(e, (touch) => { if(this.onlyView && touch.target != this.view) { return; } this.onMouseDownCallback(touch.identifier, touch.clientX, touch.clientY, touch); }); document.addEventListener("touchmove", this.touchMoveHandler, {passive: false}); document.addEventListener("touchend", this.touchEndHandler); document.addEventListener("touchcancel", this.touchEndHandler); } DragUtil.prototype._touchMoveHandler = function(e) { if(this.prevent) { e.preventDefault(); } if(this.stop) { e.stopPropagation(); } this.forEachTouch(e, function(touch) { this.onMouseMoveCallback(touch.identifier, touch.clientX, touch.clientY, touch); }); } DragUtil.prototype._touchEndHandler = function(e) { this.removeTouchListeners(); this.forEachTouch(e, function(touch) { this.onMouseUpCallback(touch.identifier, touch.clientX, touch.clientY, touch); }); } DragUtil.prototype.removeTouchListeners = function() { document.removeEventListener("touchmove", this.touchMoveHandler); document.removeEventListener("touchend", this.touchEndHandler); document.removeEventListener("touchcancel", this.touchEndHandler); }
测试代码(index.html)
<!DOCTYPE html> <html> <head> <title>拖拽工具</title> <script type="text/javascript" src="./dragUtil.js"></script> <script type="text/javascript"> var div; var drag; function onLoad() { div = document.querySelector(".cube"); drag = new DragUtil(div, null, dragMove, null, true, false, false); } function dragMove(id, x, y, dx, dy, e) { div.style.left = parseFloat(div.style.left) + dx + "px"; div.style.top = parseFloat(div.style.top) + dy + "px"; } </script> </head> <body onload="onLoad()"> <div class="cube" style="position:absolute;left: 0px;top:0px;width: 100px;height: 100px;background-color: red;cursor: move;"></div> </body> </html>
使用很简单,创建一个DrageUtil实例,传入要响应鼠标事件的dom元素,传入回调函数。
用完之后,可以调用destroy进行销毁。
参数说明:
view:响应鼠标事件的dom元素,一般为要拖拽的元素,也可以不是
mouseDownCallback:鼠标按下时回调,回调参数为:id,x,y,e,鼠标事件,id为-1,如果是触屏,可以用来区分不同的touch点,x,y为全局坐标,e为原始的事件。
mouseMoveCallback: 鼠标按下状态移动时回调,参数为id,x,y,dx,dy,e,多了个dx,dy,相对于上次移动的相对距离,也是全局坐标。
mouseUpCallback:鼠标抬起时回调,参数为id,x,y,e。
onlyView:是否只有当鼠标事件的target是view时才生效,比如如果view有子元素,这个参数可以控制在子元素上按下鼠标是否生效
prevent:是否调用preventDefault,建议不要调用。
stop:是否调用stopPropagation,建议不要调用。
一般拖拽,只需要处理mouseMoveCallback就行了,在回调中,将拖拽对象的坐标移动dx,dy,如果需要,自己转换一下坐标系。
对于canvas游戏引擎,同样可用。如果需要,可以做适当调整。代码也比较简单。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。