原生JS实现拖拽

    科技2023-10-21  95

    文章目录

    思路注意要点进阶实现回放拖拽轨迹实现倒放拖拽轨迹 实现效果完整代码

    思路

    被拖拽的元素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'); // 鼠标和拖动框的差异的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>
    Processed: 0.030, SQL: 8