如何使用 js 来完成拖拽功能
实现 div 元素的拖拽功能可以通过原生 JavaScript 来实现,主要依赖鼠标事件 mousedown、mousemove 和 mouseup 来捕获拖拽动作。以下是关键步骤的技术细节:
技术细节
-
捕获
mousedown事件:- 当用户按下鼠标时,我们开始记录当前鼠标的位置。
- 通过
event.clientX和event.clientY获取鼠标的初始坐标。 - 同时记录
div的当前位置,以便在拖拽时计算新的位置。
-
在
mousemove事件中计算新位置:- 当鼠标移动时,监听
mousemove事件。 - 通过
event.clientX和event.clientY获取当前鼠标的位置。 - 计算鼠标移动的距离(
dx和dy),并根据初始位置更新div的top和left样式,使其跟随鼠标移动。
- 当鼠标移动时,监听
-
释放鼠标(
mouseup)时停止拖拽:- 当用户释放鼠标时,移除对
mousemove和mouseup事件的监听,结束拖拽。
- 当用户释放鼠标时,移除对
-
设置
div的样式:- 为了能移动
div,需要为其设置position: absolute或position: 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: absolute或position: fixed:确保div能够在页面上自由移动。position: relative是不适用的,因为它相对父容器进行定位。event.preventDefault():阻止浏览器的默认行为(比如拖拽时文本的选择),提升用户体验。- 事件处理:
mousedown:开始拖拽。mousemove:根据鼠标的位移实时更新div位置。mouseup:结束拖拽,移除mousemove和mouseup的事件监听。
处理拖拽边界问题
要限制拖拽元素的移动范围,可以通过判断元素的当前位置,并在 mousemove 事件中做出相应的调整,以防止它超出预定的边界。以下是一些常见的处理移动范围边界的方式和具体的技术细节。
技术细节
-
获取容器的尺寸:
- 如果你希望限制
div的移动范围在某个父容器内,可以使用container.getBoundingClientRect()获取容器的尺寸和位置。 - 如果你希望限制
div的移动范围在窗口内,则可以使用window.innerWidth和window.innerHeight来获取窗口的宽高。
- 如果你希望限制
-
计算拖拽的边界:
- 在
mousemove事件中,计算出div的当前位置后,需要判断该位置是否超出容器或窗口的边界。 - 设置拖拽的最大和最小位置,确保
div不会超出这些范围。
- 在
-
调整
left和top:- 在更新
div的left和top值时,如果超出了边界,需要将其值调整到边界的最大或最小值。
- 在更新
边界处理的代码示例
假设我们限制 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>
解释关键步骤
-
窗口尺寸获取:
window.innerWidth和window.innerHeight:这两个值分别获取窗口的宽度和高度,以便知道元素是否超出屏幕的可视范围。
-
拖拽边界计算:
- 在
mousemove事件中,我们对计算出的newLeft和newTop进行限制: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 容器的范围内。
本文采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
相关文章
在 Linux 系统中如何使用 yum 安装 nginx?
在Linux系统中,使用yum来安装Nginx的步骤如下:具体步骤更新软件包仓库:确保你的软件包仓库是最新的。运行以下命令来更新:<sp
把服务器迁移到阿里云了
之前贪便宜花了几百块买了华为云的ecs服务器,服务运行了一年多懒得换,但是最近华为云要求域名必须在华为云备案才可以解析,否则域名解析会被做阻断处理,于是索性把服务迁移到阿里云,毕竟阿里云的服务比华为云强的不是一点。linux用的不是很熟,尤其是装一些必备的服务,这次做个笔记...
俄罗斯方块生成算法
俄罗斯方块是一款经典的拼图游戏,其核心算法包含方块生成、方块移动、旋转、碰撞检测等功能。我们这里重点介绍方块生成的算法,并使用JavaScript实现它。1.方块生成逻辑俄罗斯方块中的方块称为「Tetrominoes」,一共有7种不同的形状,每种形状由4个方块组成。它们通常...
