概述
拖拽这个功能,一般用的不多,不过,可以用来做一些有意思的东西,一般业务里面,常见的是拖拽上传文件,这里记录一下拖拽的实现,以及一些注意事项。
效果
事件
拖拽事件分为了三个
- mousedown:绑定到需要进行拖拽的元素上
- mousemove:绑定到需要脱拽的document上
- mouseup:绑定到document上,一般拖拽鼠标抬起的时候,清除绑定的move和up事件,避免出现事件在鼠标都抬起了,事件还在触发。
实现原理
首先需要知道鼠标事件对象和dom元素的几个属性:
- e.clientX :鼠标点到页面最左侧的距离
- e.clientY :鼠标点到页面最顶部的距离
- dom.offsetLeft:dom元素距离定位父级左侧的距离,没有定位父级为默认为页面边缘
- dom.offsetTop:dom元素距离定位父级顶部的距离,没有定位父级为默认为页面边缘
当我们在拖拽过程中,鼠标点距离元素最左侧和最上面的距离是不变的,因此我们可以在dom元素被按下的时候求出来,如下图,按下拖拽过程中,这段距离是不变的,我们可以求出来。
//方法1:
let offsetLeft = e.clientX - test.offsetLeft;//水平鼠标点距离dom元素左边的距离
let offsetTop = e.clientY - test.offsetTop;//垂直鼠标点距离dom元素左边的距离
//方法2:offsetX可以直接获取鼠标点到元素最左边和最上面的距离,但是这个属性是实验性的,不推荐
let offsetLeft = e.offsetX;
let offsetTop = e.offsetX;
因此拖拽过程中,我们只需要计算对应定位的left和top距离就可以了,距离计算看下图:
鼠标移动过程中,只需要那e.clientX减去上面计算出来的offsetLeft就行啦
dom.style.left = e.clientX - offsetLeft + 'px';
dom.style.top = e.clientY - offsetTop + 'px';
这样我们就可以拖拽生效了,但是当我们鼠标离开后,应该清除鼠标移动事件和抬起事件,避免鼠标离开了,但是鼠标拖拽还在生效。
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.test {
width: 100px;
height: 100px;
background-color: #008c8c;
/* 拖动元素记得定位 */
position: relative;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div class="test"></div>
<script>
let test = document.querySelector('.test');
// dom元素按下事件
test.addEventListener('mousedown', e => {
// 记录鼠标点到元素左边和顶部的距离
let offsetLeft = e.clientX - test.offsetLeft;
let offsetTop = e.clientY - test.offsetTop;
// 拖动事件
function moveMove(e) {
// 计算left和top的位移
test.style.left = e.clientX - offsetLeft + 'px';
test.style.top = e.clientY - offsetTop + 'px';
}
// 抬起事件
function mouseup(e) {
// 移除事件
document.removeEventListener('mousemove', moveMove);
document.removeEventListener('mouseup', mouseup);
}
// 添加拖动和抬起事件
document.addEventListener('mousemove', moveMove);
document.addEventListener('mouseup', mouseup);
// 移除默认事件和冒泡
return false;
});
</script>
</body>
</html>