快速拖动元素失效问题原因及解决方法
情景再现
晚上在写毕设时,碰到个快速拖动元素,元素会跟不上的问题。具体情形如下:
代码及演示结果
- 出现的问题
- 绑定在
document
或body
上 - 绑定在
div
自己身上
解决方案
-
首先,自己的思路是
div
之前已经绑定mousedown
事件,再绑定mousemove
事件,绑定事件过多从而出现快速移动失效问题。但这思路自己都感觉是错的,于是网上搜索相关问题,从一篇文章中找到了其中的原因,原因如下:鼠标滑动地太快,自然会造成
mousemove
事件多次发生,相应的,事件处理函数也多次被调用,自然造成延迟。延迟之后,元素移动的速度赶不上鼠标移动的速度,可能造成鼠标移出元素的状态,从而触发了mouseout
事件,从而造成了被拖动元素停止移动。 ——原文来自 鸢飞鱼跃
绑定到body
与 document
之间的细微差别
上面讲到,绑定 mousemove
事件到 body
或 document
上,都能拖动地很流畅,但是它们之间还是有些细微差别的,如下图所示:
- 绑定到
document
上 - 绑定到
body
上
在 Chrome
测试结果中可以看到,绑定到 document
上时,鼠标移动到菜单栏上,元素依旧能被拖动,而绑定在 body
上却做不到这一点。
代码
最后,以下是本次测试中用到的代码,感兴趣的小伙伴可以贴下来自己跑一跑
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
*{
padding:0;
margin:0;
}
div{
position:absolute;
left:100px;
top:50px;
width:100px;
height:100px;
border:1px solid #000;
}
body{
width:100vw;
height:100vh;
}
</style>
</head>
<body>
<div>Drag Me</div>
<script>
const div = document.querySelector('div');
const body = document.body;
div.addEventListener('mousedown',(event) => {
let startX = event.clientX,
startY = event.clientY,
left = div.offsetLeft,
top = div.offsetTop;
let callback = (event) => {
const stepX = event.clientX - startX,
stepY = event.clientY - startY;
div.style.left = `${left + stepX}px`;
div.style.top = `${top + stepY}px`;
};
document.addEventListener('mousemove',callback);
div.addEventListener('mouseup',() => {
document.removeEventListener('mousemove',callback);
});
});
</script>
</body>
</html>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。