20
2024
09

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游戏引擎,同样可用。如果需要,可以做适当调整。代码也比较简单。




源码打包下载

« 上一篇下一篇 »

相关文章:

js窗口组件  (2024-9-20 11:2:38)

SplitPanel-窗口拆分工具库  (2024-9-20 10:3:50)

js中学物理仿真  (2022-9-27 9:16:49)

显示fps  (2020-1-19 9:16:17)

js保留有效数字  (2019-7-30 15:32:12)

js的parseInt方法  (2019-2-15 9:12:44)

闪电效果  (2017-11-28 15:4:19)

js中判断一个对象的类型  (2017-3-30 14:27:35)

解九连环  (2016-12-1 20:58:11)

DataURL与File,Blob,canvas对象之间的互相转换的Javascript  (2016-11-25 14:58:41)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。