JavaScript 拖拽事件
一、拖拽
拖拽的要求是当鼠标在方块上面时,按下鼠标键挪动,方块跟着鼠标挪动,然后抬起鼠标键方块停止,再挪动鼠标这个方块不跟着鼠标挪动了,这是拖拽的一个过程,下面来写这个拖拽。
1、首先获取鼠标移动的位置
首先鼠标移动到每一位置的时候,记录一下鼠标移动位置的点,在document上绑定一个事件onmousemove,当鼠标移动的时候触发这个事件
document.onmousemove = function(e){ var event = e || window.event; // "window.event"只有在全局的时候可以换省略"window"在局部不能省略"window.event"。 console.log(event.clientY +" "+ event.clientX); // "e.clientY/e.clientX"记录当前鼠标点的位置 }
在页面移动鼠标,能把鼠标的坐标点记录下来
2、把鼠标移动的坐标,放到方块元素里面
有了鼠标坐标点位置,把这个坐标点的位置放到红色方块里面去,红色方块就跟着鼠标动了。
注意:div元素的left、top这两个属性必须设置为数字0,不然默认值是auto
<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div> <script> var div = document.getElementsByTagName('div')[0]; // 选中div元素 document.onmousemove = function(e){ var e = e || window.event; console.log(e.clientY +" "+ e.clientX); div.style.top = e.clientY + 'px'; div.style.left = e.clientX + 'px'; } </script>
鼠标可以拖动方块元素了,但动的不太好,移动时鼠标总是在方块元素的左上角
3、把事件顺序写好
1). 先不让div直接移动 div.onmousemove,
2). 先鼠标按下之后 div.onmousedown
3). 然后才绑定document,事件移动document.onmousemove
这样在红色方块上用鼠标按下,按完之后就拖拽着红色方块移动了
<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div> <script> var div = document.getElementsByTagName('div')[0]; div.onmousedown = function(e){ // 1. 先div.onmousedown按下去之后 document.onmousemove = function(e){ // 2. 绑定一个事件"document.onmousemove var e = e || window.event; div.style.top = e.clientY + 'px'; div.style.left = e.clientX + 'px'; } } </script>
4). 然后鼠标按键抬起之后,取消移动onmousemove事件
<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div> <script> var div = document.getElementsByTagName('div')[0]; div.onmousedown = function() { div.onmousemove = function(e){ // 1. 这不设置document.onmousedown,设置div.onmousedown也行,设置div更精准 var e = e || window.event; div.style.top = e.clientY + 'px'; div.style.left = e.clientX + 'px'; } div.onmouseup = function(){ // 2. 鼠标抬起也设置在div上 div.onmousemove = null; // 3. 然后鼠标抬起取消这个事件 } } </script>
点击拖走的过程完成了,但有个小问题鼠标在div的左上角,应该鼠标点击哪,哪就着跟拖走。
4、解决鼠标在div左上角的问题
我们设置鼠标当前的位置直接是方块的top和left,但是top和left是方块的左顶点,鼠标设置成左顶点肯定少了一个距离,把距离算上就行了。
鼠标当前的位置加上这个距离,再赋给方块左上角就行了,这个距离怎么求?
<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div> <script> var div = document.getElementsByTagName('div')[0], disX, disY; div.onmousedown = function(e) { var e = e || window.event; // 求第一次鼠标点击的时候"点": e.pageX // 方块左上角的距离: div.style.left disX = e.pageX - parseInt(div.style.left); // 求鼠标当前点距方块left少的这个距离 disY = e.pageY - parseInt(div.style.top); // 求鼠标当前点距方块top少的这个距离 div.onmousemove = function(e){ var e = e || window.event; div.style.top = e.clientY - disY + 'px'; // 减去这个距离 div.style.left = e.clientX - disX + 'px'; // 减去这个距离 } div.onmouseup = function(){ div.onmousemove = null; } } </script>
这样一个方块拖拽的基本功能就完成了,但是还是不好,比如飞快的往左上角一拖鼠标就出去了,但是鼠标还没抬起来,问题出那?
5、解决
我们把事件onmousemove绑定到div上了,只有在div上面挪动鼠标才能拖动,要知道鼠标的挪动是受系统监控的。
鼠标挪动是靠屏幕的帧频系统来监控的,每一秒鼠标可以够挪动多少下。比如每一秒鼠标可能挪动一百下,但是每一秒系统对事件的监听达不到一百次。
也就是说系统要监听什么时候发生事件,可能还没等系统反应过来鼠标已挪出去了,可能10毫秒监听一次什么时候挪,但你一毫秒就挪出了,系统都没监听到鼠标。
鼠标挪动的频次太快了,监听事件的频次没有那么快,所以鼠标都出了div的方块了,系统都没监听到鼠标在div上移动,还是div的面积太小了。
还想让鼠标随意的挪那么快的挪动,还想让div跟住鼠标怎么办?
<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div> <script> var div = document.getElementsByTagName('div')[0], disX, disY; div.onmousedown = function(e) { disX = e.pageX - parseInt(div.style.left); disY = e.pageY - parseInt(div.style.top); // div.onmousemove = function(e){ // 鼠标移动跟div没有关系 // 把div改成doucment上触发解除事件,在document上怎么挪都不出去document是整个屏幕。 document.onmousemove = function(e){ var e = e || window.event; div.style.top = e.clientY - disY + 'px'; div.style.left = e.clientX - disX + 'px'; } // 这也跟着改成在doucment上触发解除事件 document.onmouseup = function(){ document.onmousemove = null; } } </script>
二、封装拖拽drap()方法
<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div> <script> function dray(elem) { var disX, disY; elem.onmousedown = function(e) { disX = e.pageX - parseInt(elem.style.left); disY = e.pageY - parseInt(elem.style.top); document.onmousemove = function(e){ var e = e || window.event; elem.style.top = e.clientY - disY + 'px'; elem.style.left = e.clientX - disX + 'px'; } document.onmouseup = function(){ document.onmousemove = null; } } } var div = document.getElementsByTagName('div')[0]; dray(div); </script>
作业:
用事件监听的方式绑定事件,然后封装一个函数drag
拖拽addEvent是绑定事件兼容性写法,stopBubble取消冒泡,canceHandler阻止默认事件。
上面的鼠标位置还有一个简单的方法,直接把鼠标设置定位在方块中间的位置。
<div style="width:100px;height:100px;background-color:red;color:#fff;text-align:center;line-height:100px;position:absolute;left:0;top:0"></div> <script> var div = document.getElementsByTagName('div')[0]; div.onmousedown = function() { this.innerHTML = '别放开'; div.onmousemove = function(e){ var e = e || window.event; div.style.top = e.clientY - 100/2 + 'px'; div.style.left = e.clientX - 100/2 + 'px'; } div.onmouseup = function(){ div.onmousemove = null; this.innerHTML = '休息一会吧'; } } </script>
三、setCapture()
拓展一下,这是一个过时的问题,但有些面试官会问一下符合他那个年代的问题,他会问什么是"事件获取"?
回答addEventListener第三个参数为true的时候,面试官还会问你还有没有其它形式的捕获,他说的什么意思呢?
我们说事件处理模型一个是冒泡一个是捕获这是毋庸置疑的,他说的第二种捕获不是事件处理模型,而是一种真实的事件获取的过程,用以解决这种拖拽鼠标容易出了div这样麻烦事。
用于解决鼠标帧频比事件监听帧频要快的问题,我们是用document绑定这种方式解决的。
他不是这样解决的,还有一种方法也叫事件捕获仅在IE里面好使叫"div.setCapture()"是个方法,执行完这个方法,这个div会获取捕获页面上发生的所有的事件,硬捕获到自己身上。
div.setCapture();
比如鼠标挪出div了,在其它地方发生的任何事情都算到div自己身上,这也叫事件获取依然能解决刚才的问题。
用完后用对应的方法"div.releaseCapture()"给释放了,这两个函数是对应的。
div.setCapture(); div.releaseCapture();
但这两个方法记住就行不用会操作,因为只有IE能用也不通用。
"Capture"获得、博得的意思。