文章目录
思路注意要点进阶实现回放拖拽轨迹实现倒放拖拽轨迹
实现效果完整代码
思路
被拖拽的元素eDrag要使用绝对定位,脱离文档流才可以移动。
鼠标点击:isDragged(当前eDrag是否被拖拽的标识)设置为true,a= 获取当前鼠标坐标、b = eDrag盒子左上角的坐标、c = 鼠标在div内部距离=a-b=(offsetX, offsetY)。
鼠标移动:通过 b = a - c = a - (a - b) 建立鼠标与eDrag的关系,注意处理盒子到达浏览器边界的情况,防止eDrag超出浏览器。
鼠标抬起:isDragged(当前eDrag是否被拖拽的标识)设置为false
注意要点
eDrag.offsetLeft、eDrag.offsetTop分别代表eDrag的盒子的左上角与浏览器视图左边界和上边界的距离,即浏览器左上角为原点(0,0),width为x轴,height为y轴。鼠标在eDrag内点击时的一刻,鼠标的坐标(x1,y1)与eDrag盒子左上角的坐标(x2,y2),一定有:x1>=x2,y1>=y2。鼠标移动时,分别针对eDrag左上角坐标b(x,y)的x和y来讨论边界处理的情况。
进阶
使用一个轨迹数组,每次鼠标拖拽时,将当前eDrag的(x,y)存入数组。
实现回放拖拽轨迹
队列的使用,使用Array.prototype.shift()不断从队头(数组头)拿轨迹位置数据。
实现倒放拖拽轨迹
栈的使用,使用Array.prototype.pop()不断从栈尾(数组尾)拿轨迹位置数据。
实现效果
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title
</title>
<style>
body, div, h2, p {
margin: 0;
padding: 0;
}
body {
background-color: #666666;
}
.box {
position: absolute;
width: 300px;
background: blue;
cursor: move;
border: 2px solid black;
top: 50%;
left: 50%;
}
.box h2 {
color: white;
font-size: 20px;
line-height: 1em;
background-color: #222;
border-bottom: 2px solid #ccc;
text-align: center;
padding: 0 10px;
}
.box p {
color: white;
}
#backtrack {
border-top: 1px solid black;
padding: 0 10px;
vertical-align: bottom;
text-align: right;
}
#backtrack a {
text-decoration: none;
color: white;
}
#backtrack a:hover {
text-decoration: underline;
color: black;
}
.notClick{
pointer-events: none;
}
</style>
</head>
<body>
<div class="box" id="eDrag">
<h2>一个寂寞的拖拽框
</h2>
<p><strong>isDragged:
</strong><span id="eIsDragged">false
</span></p>
<p><strong>offsetTop:
</strong><span id="eOffsetTop">229
</span></p>
<p><strong>offsetLeft:
</strong><span id="eOffsetLeft">385
</span></p>
<p id="backtrack">
<a id="aPlayback" href="javascript:">点此回放拖动轨迹
</a>
<a id="aBacktrack" href="javascript:">点此倒放拖动轨迹
</a>
</p>
</div>
<script>
let eDrag = document.getElementById('eDrag');
let eIsDragged = document.getElementById('eIsDragged');
let eOffsetTop = document.getElementById('eOffsetTop');
let eOffsetLeft = document.getElementById('eOffsetLeft');
let aPlayback = document.getElementById('aPlayback');
let aBackTrack = document.getElementById('aBacktrack');
let diffX = 0;
let diffY = 0;
let nowX = eDrag.offsetLeft;
let nowY = eDrag.offsetTop;
let isDragged = false;
let positionArray = [
{
x: eDrag.offsetLeft,
y: eDrag.offsetTop,
}
]
function updateShowInfo() {
eIsDragged.innerText = isDragged;
eOffsetTop.innerText = nowY;
eOffsetLeft.innerText = nowX;
}
function moveTarget(target, x, y) {
target.style.left = x + 'px';
target.style.top = y + 'px';
}
eDrag.onmousedown = function (event) {
event = event || window.event;
isDragged = true;
diffX = event.clientX - eDrag.offsetLeft;
diffY = event.clientY - eDrag.offsetTop;
if (typeof eDrag.setCapture !== "undefined") {
eDrag.setCapture();
}
}
document.onmousemove = function (event) {
if (!isDragged) {
return;
}
event = event || window.event;
nowX = event.clientX - diffX;
nowY = event.clientY - diffY;
if (nowX < 0) {
nowX = 0;
} else if (nowX > window.innerWidth - eDrag.offsetWidth) {
nowX = window.innerWidth - eDrag.offsetWidth;
}
if (nowY < 0) {
nowY = 0;
} else if (nowY > window.innerHeight - eDrag.offsetHeight) {
nowY = window.innerHeight - eDrag.offsetHeight;
}
positionArray.push(
{
x: nowX,
y: nowY,
}
)
moveTarget(eDrag, nowX, nowY)
updateShowInfo();
}
document.onmouseup = window.onblur = eDrag.onlosecapture = function (event) {
isDragged = false;
if (typeof eDrag.releaseCapture != "undefined") {
eDrag.releaseCapture();
}
updateShowInfo();
}
aPlayback.onclick = function () {
if (positionArray.length === 1)
return;
let timer = setInterval(function () {
let tmpPos = positionArray.shift();
if (tmpPos) {
moveTarget(eDrag, tmpPos.x, tmpPos.y);
} else {
clearInterval(timer);
}
}, 33);
};
aBackTrack.onclick = function () {
if (positionArray.length === 1)
return;
let timer = setInterval(function () {
let tmpPos = positionArray.pop();
if (tmpPos) {
moveTarget(eDrag, tmpPos.x, tmpPos.y);
} else {
clearInterval(timer);
}
}, 33);
};
updateShowInfo();
</script>
</body>
</html>