拖动元素首先我们得明确整个拖动事件中相关的元素,我总结有3个相关元素:
- 拖动的元素: 目标元素
- 触发拖动事件的元素:绑定
mousedown
事件的元素,它可能就是目标元素 - 响应目标元素的元素:绑定
mousemove
事件的元素,它是为了响应拖动元素的移动的,后面统称父元素
获取鼠标初始位置
function getScrollOffset(w) {
w = w || window;
if (w.pageXOffset != null) return { x: w.pageXOffset, y: w.pageYOffset };
var d =w.document;
if (document.compatMode === "CSS1Compat")
return { x: d.documentElement.scrollLeft, y:d.documentElement.scrollTop };
return { x: d.body.scrollLeft, y: d.body.scrollTop };
}
const scroll = getScrollOffset();
const startX = e.clientX + scroll.x;
const startY = e.clientY + scroll.y;
复制代码
注意: clientX 事件属性返回当事件被触发时鼠标指针向对于浏览器页面(或客户区)的水平坐标,所以我们必须考虑页面滚动的情况。
获取目标元素到父元素的距离
function getTargetLeft(element, parent = null) {
let offsetLeft = element.offsetLeft;
let current = element.offsetParent;
while (current !== parent) {
offsetLeft += current.offsetLeft;
current = current.offsetParent
}
return offsetLeft;
}
function getTargetTop(element, parent = null) {
let offsetTop = element.offsetTop;
let current = element.offsetParent;
while (current !== parent) {
offsetTop += current.offsetTop;
current = current.offsetParent
}
return offsetTop;
}
const origX = getTargetLeft(e.target);
const origY = getTargetTop(e.target);
复制代码
获取鼠标相对mousedown事件元素的距离
const deltaX = startX - origX;
const deltaY = startY - origY;
复制代码
整合后完整代码
html
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="droptarget" style="width: 100px; height: 100px; background: red; position: absolute;">
<div onmousedown="drag(this.parentNode, event)">title</div>
<p>测试测试</p>
</div>
</body>
复制代码
drag.js
function getScrollOffset(w) {
w = w || window;
if (w.pageXOffset != null) return { x: w.pageXOffset, y: w.pageYOffset };
var d =w.document;
if (document.compatMode === "CSS1Compat")
return { x: d.documentElement.scrollLeft, y:d.documentElement.scrollTop };
return { x: d.body.scrollLeft, y: d.body.scrollTop };
}
function drag(targetElement, e) {
const scroll = getScrollOffset();
const startX = e.clientX + scroll.x;
const startY = e.clientY + scroll.y;
function getTargetLeft(element, parent = null) {
let offsetLeft = element.offsetLeft;
let current = element.offsetParent;
while (current !== parent) {
offsetLeft += current.offsetLeft;
current = current.offsetParent
}
return offsetLeft;
}
function getTargetTop(element, parent = null) {
let offsetTop = element.offsetTop;
let current = element.offsetParent;
while (current !== parent) {
offsetTop += current.offsetTop;
current = current.offsetParent
}
return offsetTop;
}
const origX = getTargetLeft(e.target);
const origY = getTargetTop(e.target);
const deltaX = startX - origX;
const deltaY = startY - origY;
document.addEventListener("mousemove", moveHandler, true);
document.addEventListener("mouseup", upHandler, true);
function moveHandler(e) {
const scroll = getScrollOffset();
targetElement.style.left = (e.clientX + scroll.x - deltaX) + "px";
targetElement.style.top = (e.clientY + scroll.y - deltaY) + "px";
e.stopPropagation();
}
function upHandler(e) {
document.removeEventListener("mouseup", upHandler, true);
document.removeEventListener("mousemove", moveHandler, true);
e.stopPropagation();
}
}
复制代码