思路
-
被拖拽的元素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()不断从栈尾(数组尾)拿轨迹位置数据。
实现效果
![[js效果]原生JS实现拖拽 [js效果]原生JS实现拖拽](https://www.bmabk.com/wp-content/uploads/2022/05/post-loading.gif)
完整代码
<!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');
// 鼠标和拖动框的差异的x和y值
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;
}
// console.log("拖动中")
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)
// 更新显示信息
// console.log(nowX + 'px', nowY + 'px')
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>
原文始发于微信公众号(豆子前端):[js效果]原生JS实现拖拽
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/56806.html