如何使用 js 来完成拖拽功能

发布时间:2024-10-07

实现 div 元素的拖拽功能可以通过原生 JavaScript 来实现,主要依赖鼠标事件 mousedownmousemovemouseup 来捕获拖拽动作。以下是关键步骤的技术细节:

技术细节

  1. 捕获 mousedown 事件

    • 当用户按下鼠标时,我们开始记录当前鼠标的位置。
    • 通过 event.clientXevent.clientY 获取鼠标的初始坐标。
    • 同时记录 div 的当前位置,以便在拖拽时计算新的位置。
  2. mousemove 事件中计算新位置

    • 当鼠标移动时,监听 mousemove 事件。
    • 通过 event.clientXevent.clientY 获取当前鼠标的位置。
    • 计算鼠标移动的距离(dxdy),并根据初始位置更新 divtopleft 样式,使其跟随鼠标移动。
  3. 释放鼠标(mouseup)时停止拖拽

    • 当用户释放鼠标时,移除对 mousemovemouseup 事件的监听,结束拖拽。
  4. 设置 div 的样式

    • 为了能移动 div,需要为其设置 position: absoluteposition: fixed

代码示例

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Draggable DIV</title> <style> #draggable { width: 150px; height: 150px; background-color: lightblue; position: absolute; /* 关键点 */ top: 100px; left: 100px; cursor: grab; } </style> </head> <body> <div id="draggable">Drag me!</div> <script> const draggable = document.getElementById("draggable"); let isDragging = false; // 标记是否正在拖拽 let startX, startY, initialLeft, initialTop; draggable.addEventListener("mousedown", (event) => { isDragging = true; // 记录鼠标按下时的位置 startX = event.clientX; startY = event.clientY; // 获取 div 的当前偏移量 initialLeft = draggable.offsetLeft; initialTop = draggable.offsetTop; // 设置样式改变鼠标指针为拖拽状态 draggable.style.cursor = "grabbing"; // 防止文本被意外选中 event.preventDefault(); }); document.addEventListener("mousemove", (event) => { if (isDragging) { // 计算移动的距离 const dx = event.clientX - startX; const dy = event.clientY - startY; // 更新 div 的位置 draggable.style.left = `${initialLeft + dx}px`; draggable.style.top = `${initialTop + dy}px`; } }); document.addEventListener("mouseup", () => { if (isDragging) { isDragging = false; draggable.style.cursor = "grab"; // 恢复光标样式 } }); </script> </body> </html>

关键点分析

  • position: absoluteposition: fixed:确保 div 能够在页面上自由移动。position: relative 是不适用的,因为它相对父容器进行定位。
  • event.preventDefault():阻止浏览器的默认行为(比如拖拽时文本的选择),提升用户体验。
  • 事件处理
    • mousedown:开始拖拽。
    • mousemove:根据鼠标的位移实时更新 div 位置。
    • mouseup:结束拖拽,移除 mousemovemouseup 的事件监听。

处理拖拽边界问题

要限制拖拽元素的移动范围,可以通过判断元素的当前位置,并在 mousemove 事件中做出相应的调整,以防止它超出预定的边界。以下是一些常见的处理移动范围边界的方式和具体的技术细节。

技术细节

  1. 获取容器的尺寸

    • 如果你希望限制 div 的移动范围在某个父容器内,可以使用 container.getBoundingClientRect() 获取容器的尺寸和位置。
    • 如果你希望限制 div 的移动范围在窗口内,则可以使用 window.innerWidthwindow.innerHeight 来获取窗口的宽高。
  2. 计算拖拽的边界

    • mousemove 事件中,计算出 div 的当前位置后,需要判断该位置是否超出容器或窗口的边界。
    • 设置拖拽的最大和最小位置,确保 div 不会超出这些范围。
  3. 调整 lefttop

    • 在更新 divlefttop 值时,如果超出了边界,需要将其值调整到边界的最大或最小值。

边界处理的代码示例

假设我们限制 div 在窗口内移动:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Draggable DIV with Boundaries</title> <style> #draggable { width: 150px; height: 150px; background-color: lightblue; position: absolute; top: 100px; left: 100px; cursor: grab; } </style> </head> <body> <div id="draggable">Drag me!</div> <script> const draggable = document.getElementById("draggable"); let isDragging = false; let startX, startY, initialLeft, initialTop; draggable.addEventListener("mousedown", (event) => { isDragging = true; // 记录鼠标按下时的位置 startX = event.clientX; startY = event.clientY; // 获取 div 的当前偏移量 initialLeft = draggable.offsetLeft; initialTop = draggable.offsetTop; // 设置样式改变鼠标指针为拖拽状态 draggable.style.cursor = "grabbing"; // 防止文本被意外选中 event.preventDefault(); }); document.addEventListener("mousemove", (event) => { if (isDragging) { // 计算移动的距离 const dx = event.clientX - startX; const dy = event.clientY - startY; // 计算新的位置 let newLeft = initialLeft + dx; let newTop = initialTop + dy; // 获取窗口的宽度和高度 const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; // 获取 div 的宽度和高度 const divWidth = draggable.offsetWidth; const divHeight = draggable.offsetHeight; // 限制 newLeft 和 newTop 在窗口内 if (newLeft < 0) newLeft = 0; if (newTop < 0) newTop = 0; if (newLeft + divWidth > windowWidth) newLeft = windowWidth - divWidth; if (newTop + divHeight > windowHeight) newTop = windowHeight - divHeight; // 更新 div 的位置 draggable.style.left = `${newLeft}px`; draggable.style.top = `${newTop}px`; } }); document.addEventListener("mouseup", () => { if (isDragging) { isDragging = false; draggable.style.cursor = "grab"; } }); </script> </body> </html>

解释关键步骤

  1. 窗口尺寸获取

    • window.innerWidthwindow.innerHeight:这两个值分别获取窗口的宽度和高度,以便知道元素是否超出屏幕的可视范围。
  2. 拖拽边界计算

    • mousemove 事件中,我们对计算出的 newLeftnewTop 进行限制:
      • newLeft < 0:限制拖拽区域不能超过左边界(最小为 0)。
      • newTop < 0:限制拖拽区域不能超过上边界(最小为 0)。
      • newLeft + divWidth > windowWidth:如果 div 的右边缘超过窗口宽度,调整 newLeft 以保持 div 的右边缘在窗口内。
      • newTop + divHeight > windowHeight:如果 div 的底边缘超过窗口高度,调整 newTop 以保持 div 的底边缘在窗口内。

扩展:限制在父容器内

如果你想将拖拽限制在某个父容器内而不是窗口内,可以使用 container.getBoundingClientRect() 获取容器的边界信息,代码如下:

const container = document.getElementById("container"); const containerRect = container.getBoundingClientRect(); // 修改边界判断逻辑 if (newLeft < containerRect.left) newLeft = containerRect.left; if (newTop < containerRect.top) newTop = containerRect.top; if (newLeft + divWidth > containerRect.right) newLeft = containerRect.right - divWidth; if (newTop + divHeight > containerRect.bottom) newTop = containerRect.bottom - divHeight;

这样 div 的移动将会被限制在 container 容器的范围内。