0%

实现鼠标拖拽DOM

缘起,前段时间百度面试被问到了这个问题,特来做个总结

1.相关知识点

常用的鼠标事件

  • click
  • dbclick:双击
  • mouseenter:当鼠标指针首次移动到元素上时触发。不冒泡
  • mouseleave:当鼠标指针移出元素时触发。不冒泡
  • mousedown:当元素上按下鼠标按钮时候触发
  • mouseup:当元素上释放鼠标按钮时触发
  • mousemove:当鼠标指针在元素内部移动时重复地触发
  • mouseover:当鼠标指针移动到元素上时触发
  • mouseout:当鼠标指针移出元素时触发

事件对象

当触发某个事件时,会产生一个事件对象,这个对象包含着所有与事件有关的信息。会作为参数传递给函数,IE8以及之前的版本event对象是作为window对象的属性存在的。故有了以下常见的写法:function (e) { e = e || window.event; ... } 。事件对象的属性如下:

1

2

应用:

1
2
3
4
5
6
7
8
9
10
11
function stopPro(e) {
var e = e || window.event;
// 得到事件目标DOM对象
let dom = e.target || e.srcElement;
// 阻止冒泡
window.event ? e.cancelBubble = true : e.stopPropagation();
// 取消默认事件
window.event ? e.returnValue = false : e.preventDefault();
// 阻止默认行为(但会继续冒泡)
return false
}

坐标

事件对象

  • event对象.screenX / screenY :相对电脑屏幕的坐标,距离左边框和上边框的距离
  • event对象.clientX / clientY :相对浏览器可视区的坐标,同理
  • pageX、pageY : 对于整个页面来说,包括了被卷去的body部分的长度
  • offsetX、offsetY :相对于带有定位的父盒子的x,y坐标
  • x、y :和screenX、screenY一样

DOM节点

  • DOM节点.offsetLeft / offsetTop

    可以获得元素 距离上方或外层元素 的位置,本质和 style.top 是一样的。二者区别:offsetTop 返回的是数字,而 style.top 返回的是字符串,除了数字外还带有单位(px);offsetTop 只读,而 style.top 可读写。同理offsetWidth 与 style.width、offsetHeight 与 style.height

  • DOM节点.clientHeight / clientWidth

    浏览器中可视区高度。width + padding(不含border)

  • DOM节点.scrollHeight / scrollWidth

    元素内容真实的宽度,内容不超出盒子高度时为盒子的clientWidth

  • Window视图

    window.innerWidth / innerHeight:浏览器窗口可视区宽度(不包括浏览器控制台、菜单栏、工具栏) (低版本IE浏览器< IE9不支持)

2.实现

拖拽无非是鼠标按下点击元素;鼠标移动,元素移动;鼠标抬起,元素停止不动
所以这里我们需要绑定三个事件:mousedown、mousemove、mouseup

整体的思路就是:

  1. 在鼠标移动到当前元素的上方并且按下左键的事件开始
  2. 当鼠标移动的时候,改变元素的位置
  3. 当鼠标左键放开的时候,停止改变元素的位置
1
2
3
4
5
6
7
8
9
<div id="ball"></div>
#ball{
background: red;
width: 40px;
height: 40px;
border-radius: 50%;
cursor: pointer; //光标呈现为指示链接的指针(一只手)
position: absolute;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const ball = document.getElementById('ball');

let startDrag = false;

ball.addEventListener('mousedown', () => {
startDrag = true;
});
//将mousemove事件绑定到了元素本身,这意味着当鼠标移出元素所占据的范围的时候,元素会停止移动。这就是小球突然停顿的原因。
document.addEventListener('mousemove', (e) => {
if(!startDrag) return;
let x = e.pageX - ball.offsetWidth / 2;
let y = e.pageY - ball.offsetHeight / 2;
ball.style.left = `${x}px`;
ball.style.top = `${y}px`;
});

ball.addEventListener('mouseup', () => {
startDrag = false;
});
-------------本文结束感谢您的阅读-------------