js拖拽工具库
项目中经常会有拖拽功能。
自己写的一个用于拖拽的库。
先看一下效果
代码如下(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游戏引擎,同样可用。如果需要,可以做适当调整。代码也比较简单。