首页 > 技术文章 > JS拖拽原理

moranhuishou 2016-12-09 16:12 原文

实现拖拽效果主要跟鼠标的三个事件有关:    

    onmousedown : 选择要拖拽的元素
    onmousemove : 移动元素
    onmouseup : 释放元素

三个事件的关系:
		obj.onmousedown = function(ev){
			var ev = ev||event;

			var disX = ev.clientX - this.offsetLeft;
			var disY = ev.clientY - this.offsetTop;
			
			obj.ommousemove = function(ev){

				var ev = ev||event;
				obj.style.left = ev.clientX - disX + 'px';
				obj.style.top = ev.clientY - disY + 'px';

			}
			obj.onmouseup = function(){
				obj.onmousemove = null;
			}

		}

  以上代码是实现拖拽的最基本方法,但是如果鼠标移动过快脱离obj,移动就会失去效果,所以移动事件(onmousemove)应该绑定在document上面,同时onmouseup也应该绑定在document上:

obj.onmousedown = function(ev){
			var ev = ev||event;

			var disX = ev.clientX - this.offsetLeft;
			var disY = ev.clientY - this.offsetTop;
			
			document.ommousemove = function(ev){

				var ev = ev||event;
				obj.style.left = ev.clientX - disX + 'px';
				obj.style.top = ev.clientY - disY + 'px';

			}
			document.onmouseup = function(){
				obj.onmousemove = null;
			}

		}

 问题 拖拽的时候,如果有文字被选中,会产生问题

原因:当鼠标按下的时候,如果页面中有文字被选中,那么会触发浏览器默认拖拽文字的效果 ,拖拽图片也是一样,会类似复制一份出来一样,解决办法跟文字一样

  解决:
    标准:  阻止默认行为
    非标准ie:  设置全局捕获setCapture()(跟事件的捕获不是一个概念)

 

全局捕获:

例如:页面有两个input,点击input1弹出1,点击input2弹出2 ,如果我们给input1设置全局捕获,让后续的所有操作截取到input1上面,那么此时无论点击input2还是点击文档的任何地方,包括点击桌面,

  input1都会将这些点击事件截取到自己身上来执行自己的click事件,就是弹出1,这就是设置全局捕获的一个效果。

<script>
window.onload = function() {
	
	var aInput = document.getElementsByTagName('input');
	
	aInput[0].setCapture();	//设置全局捕获 ,当我们给一个元素设置全局捕获以后,那么这个元素就会监听后续发生的所有事件,当有事件发生的时候,就会被当前设置了全局捕获的元素所触发
	
	/*
	ie : 有,并且有效果
	ff : 有,但是没效果
	chrome : 没有setCapture()
	*/
	
	aInput[0].onclick = function() {
		alert(1);
	}
	
	aInput[1].onclick = function() {
		alert(2);
	}
	
}
</script>
</head>

<body>
	<input type="button" value="按钮一" />
    <input type="button" value="按钮二" />
</body>
</html>  

  但是全局捕获也是有兼容性的,

     ie : 有,并且有效果
	ff : 有,但是没效果
	chrome : 没有setCapture()

所以用的时候首先要判断元素有没有setCapture()
          if ( obj.setCapture ) {
			oDiv.setCapture();
		  } 

当鼠标抬起的时候也要释放全局捕获
releaseCapture();

所以拖拽的时候,如果有文字被选中,我们可以阻止文字的默认事件或者是利用全局捕获将所有的事件都截取到obj上,这样文字不会触发事件:

<style>
#div1 {width: 100px; height: 100px; background: red; position: absolute;}
</style>
<script>
window.onload = function() {
	
	var oDiv = document.getElementById('div1');
	
	oDiv.onmousedown = function(ev) {
		var ev = ev || event;
		
		var disX = ev.clientX - this.offsetLeft;
		var disY = ev.clientY - this.offsetTop;
		
		if ( oDiv.setCapture ) {
			oDiv.setCapture();
		}
		
		document.onmousemove = function(ev) {
			var ev = ev || event;
			
			oDiv.style.left = ev.clientX - disX + 'px';
			oDiv.style.top = ev.clientY - disY + 'px';
		}
		
		document.onmouseup = function() {
			document.onmousemove = document.onmouseup = null;
			//释放全局捕获 releaseCapture();
			if ( oDiv.releaseCapture ) {
				oDiv.releaseCapture();
			}
		}
		
		return false;
		
	}
	
}
</script>
</head>

<body>
	jafldsfjdsjfkl
	<div id="div1"></div>
</body>
</html>

 这就是拖拽的一个最基本的实现。

 

拖拽的封装 drag(obj);

<style>
#div1 {width: 100px; height: 100px; background: red; position: absolute;}
#img1 { position: absolute;}
</style>
<script>
window.onload = function() {
	
	var oDiv = document.getElementById('div1');
	var oImg = document.getElementById('img1');
	
	drag(oImg);
	drag(oDiv);
	
function drag(obj) { obj.onmousedown = function(ev) { var ev = ev || event; var disX = ev.clientX - this.offsetLeft; var disY = ev.clientY - this.offsetTop; if ( obj.setCapture ) { obj.setCapture(); } document.onmousemove = function(ev) { var ev = ev || event; obj.style.left = ev.clientX - disX + 'px'; obj.style.top = ev.clientY - disY + 'px'; } document.onmouseup = function() { document.onmousemove = document.onmouseup = null; //释放全局捕获 releaseCapture(); if ( obj.releaseCapture ) { obj.releaseCapture(); } } return false; } } } </script> </head> <body> <div id="div1"></div> <img src="1.jpg" id="img1" /> </body> </html>  

限制范围的拖拽:

先判断值,再赋值。
<style>
#div1 {width: 100px; height: 100px; background: red; position: absolute;}
#img1 { position: absolute;}
</style>
<script>
window.onload = function() {
	
	var oDiv = document.getElementById('div1');
	var oImg = document.getElementById('img1');
	
	drag(oImg);
	
	drag(oDiv);
	
	function drag(obj) {
		
		obj.onmousedown = function(ev) {
			var ev = ev || event;
			
			var disX = ev.clientX - this.offsetLeft;
			var disY = ev.clientY - this.offsetTop;
			
			if ( obj.setCapture ) {
				obj.setCapture();
			}
			
			document.onmousemove = function(ev) {
				var ev = ev || event;
				
				var L = ev.clientX - disX;
				var T = ev.clientY - disY;
				
				if ( L < 0 ) {
					L = 0;
				} else if ( L > document.documentElement.clientWidth - obj.offsetWidth ) {
					L = document.documentElement.clientWidth - obj.offsetWidth;
				}
				
				if ( T < 0 ) {
					T = 0;
				} else if ( T > document.documentElement.clientHeight - obj.offsetHeight ) {
					T = document.documentElement.clientHeight - obj.offsetHeight;
				}
				
				obj.style.left = L + 'px';
				obj.style.top = T + 'px';
				
			}
			
			document.onmouseup = function() {
				document.onmousemove = document.onmouseup = null;
				if ( obj.releaseCapture ) {
					obj.releaseCapture();
				}
			}
			
			return false;
			
		}
		
	}
	
}
</script>
</head>

<body>
	<div id="div1"></div>
    <img src="1.jpg" id="img1" />
</body>
</html>

 有一种磁性吸附的效果:

                   if ( L <100 ) {
					L = 0;
				} else if ( L > document.documentElement.clientWidth - obj.offsetWidth ) {
					L = document.documentElement.clientWidth - obj.offsetWidth;
				}
				
				

 

碰撞检测实例

<style>
#div1 {width: 100px; height: 100px; background: red; position: absolute; z-index: 2;}
#img1 { position: absolute; left: 500px; top: 200px;}
</style>
<script>
window.onload = function() {
	
	var oDiv = document.getElementById('div1');
	var oImg = document.getElementById('img1');
	
	drag(oDiv);
	
	function drag(obj) {
		
		obj.onmousedown = function(ev) {
			var ev = ev || event;
			
			var disX = ev.clientX - this.offsetLeft;
			var disY = ev.clientY - this.offsetTop;
			
			if ( obj.setCapture ) {
				obj.setCapture();
			}
			
			document.onmousemove = function(ev) {
				var ev = ev || event;
				
				var L = ev.clientX - disX;
				var T = ev.clientY - disY;
				
				var L1 = L;
				var R1 = L + obj.offsetWidth;
				var T1 = T;
				var B1 = T + obj.offsetHeight;
				
				var L2 = oImg.offsetLeft;
				var R2 = L2 + oImg.offsetWidth;
				var T2 = oImg.offsetTop;
				var B2 = T2 + oImg.offsetHeight;
				
				if ( R1 < L2 || L1 > R2 || B1 < T2 || T1 > B2 ) {
					oImg.src = '1.jpg';
				} else {
					oImg.src = '2.jpg';
				}
				
				obj.style.left = L + 'px';
				obj.style.top = T + 'px';
				
			}
			
			document.onmouseup = function() {
				document.onmousemove = document.onmouseup = null;
				if ( obj.releaseCapture ) {
					obj.releaseCapture();
				}
			}
			
			return false;
			
		}
		
	}
	
}
</script>
</head>

<body>
	<div id="div1"></div>
    <img src="1.jpg" id="img1" />
</body>
</html>

  

  

 

 

推荐阅读