js实现带边界检测的拖拽效果

很久没有更新博客了,相比以前感觉自己是有点变懒了,好在现在以前的那个我又回来了。

本文记录的是一个简单的js拖拽效果,实现使用es6语法写的,没考虑兼容性,只是简要的说明一下原理。相信看到此文的朋友一定能做出更好的效果。戳我查看效果

废话不多说,先看一下代码:

var Drag = (function(){
	let disX,disY;
	const init = function(options) {
		const { id, limit, showLimit } = options;
		const node = document.getElementById(id); 
		convertStaticNodeToAbsolute(node);
		bindEvents(node, limit);
		if (showLimit) {
			showLimitBox(limit);
		}
	}
	// 绑定事件
	const bindEvents = function(node, limit=[0, window.innerWidth, 0, window.innerHeight]){
		node.onmousedown = function(event){
			disX = event.pageX - node.offsetLeft;
			disY = event.pageY - node.offsetTop;
			document.onmousemove = function(event){
				let x = event.pageX-disX,
					y = event.pageY-disY,
					w = node.offsetWidth,
					h = node.offsetHeight;
				x = x <= limit[0] ? limit[0] : ((x>=limit[1]-w) ? limit[1]-w : x);
				y = y <= limit[2] ? limit[2] : ((y>=limit[3]-h) ? limit[3]-h : y);
				node.style.cssText = `position:absolute;left:${x}px;top:${y}px;margin:0;cursor: move`;
			}
			document.onmouseup = function(){
				document.onmousemove = null;
				document.onmouseup = null;
			}
		}
	}
	// 显示限制区域
	const showLimitBox = function(limit=[0, window.innerWidth, 0, window.innerHeight]) {
		const node = document.createElement("div");
		const width = limit[1] - limit[0];
		const height = limit[3] - limit[2];
		node.style.cssText = `position:absolute;width:${width}px;height:${height}px;top:${limit[2]}px;left:${limit[0]}px;border:1px dashed #0f0;z-index:-1;`;
		document.body.appendChild(node);
	}
	// 将静态定位的元素转换为绝对定位
	const convertStaticNodeToAbsolute = function(node){
		const top = node.offsetTop;
		const left = node.offsetLeft;
		if (node.style.position === 'absolute') {
			return;
		} else {
			node.style.cssText = `position:absolute;top:${top}px;left:${left}px;margin:0;cursor: move`;
		}
	}
	return function(options){
		init(options);
	}
})();

实现这个效果需要用到的三个事件:

1、onmousedown 鼠标左键按下时触发

2、onmousemove 鼠标移动时触发,如果不加限制,会一直触发。

3、onmouseup/onmouseout 鼠标左键释放/移开时触发。

当我们在目标元素上按下鼠标左键时,我们可以记录下一个状态鼠标按下了,然后在之后的onmousemove事件中我们先判断鼠标是否按下,如果按下我们就需要根据鼠标的移动来改变目标元素的位置,当鼠标释放,重置鼠标按下状态,之后onmousemove事件不会再更新元素位置。

但是实践发现如果我们将三个事件全部绑定在目标元素上,在快速拖动的时候会丢失目标,而且很产生一些很诡异的问题,为了更好的解决这个问题,我们在目标元素的onmousedown中监听document的onmousemove,onmousemoup事件,当鼠标释放时将document的onmousemove,onmousemoup指向为空,不影响后续别的操作。

  • 支付宝二维码 支付宝
  • 微信二维码 微信
相关文章