前端中的拖拽知识
# 概述
本文主要介绍前端中拖拽相关的知识以及如何在 vue3 工程里实现拖拽指令。
# 前端中的拖拽
前端中的拖拽功能是一种交互设计,允许用户通过鼠标或触摸操作移动页面上的元素到不同的位置。这一功能的实现涉及 HTML
、CSS
和 JavaScript
的综合运用。
# HTML元素拖拽
- 拖拽元素
HTML 元素有一个draggable
属性,接受一个布尔值,默认值为false
(不可拖拽)。
<div draggable="true">我是可拖动的</div>
1
- 事件处理
拖拽功能的实现依赖于几个关键的拖放事件:
dragstart
: 当用户开始拖动元素时触发,可以在这里设置数据传输(如拖动的数据类型和值)。drag
: 元素正在被拖动时连续触发。dragend
: 用户释放鼠标,结束拖动时触发。dragenter
和dragover
: 当拖动的元素进入或停留在目标区域时触发。通常需要阻止这两个事件的默认行为,以允许元素被放置。drop
: 在拖动元素被释放到有效目标时触发,是接收拖动数据并执行相应操作的地方。
# 示例效果
效果如下:
# 核心代码
代码如下:
dragClass.addEventListener("dragstart", (e) => {
const node = e.target.cloneNode(true);
e.dataTransfer.setData("cloneNode", node.outerHTML);
});
dragClass.addEventListener("dragend", (e) => {
e.dataTransfer.clearData();
});
dropDom.addEventListener("dragover", (e) => {
if (e.target.className == "draggable") {
e.preventDefault();
}
});
dropDom.addEventListener("drop", (e) => {
e.preventDefault();
const node = e.dataTransfer.getData("cloneNode");
e.target.innerHTML = node;
const originCellNode = e.dataTransfer.getData("text/html");
if (originCellNode) {
originCellNode.removeChild(originCellNode);
}
e.dataTransfer.clearData("cloneNode");
});
dragTableCell.addEventListener("dragstart", (e) => {
const node = e.target.cloneNode(true);
e.dataTransfer.setData("cloneNode", node.outerHTML);
e.dataTransfer.setData("text/html", e.target.parentNode.outerHTML);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 参考地址
参考地址:https://github.com/Jinuss/blog/blob/main/docs/Demo/03.drag.html (opens new window)
# vue3 拖拽指令封装
在 vue3 中实现组件的拖拽,可以封装一个拖拽指令,再需要进行拖拽的组件上加上v-drag
即可。
拖拽指令实现实现如下:
export const drag = {
mounted(el) {
el.style.position = "absolute";
el.style.cursor = "move";
let startX, startY, initialX, initialY;
const dragStart = (e) => {
startX = e.clientX;
startY = e.clientY;
initialX = el.offsetLeft;
initialY = el.offsetTop;
document.addEventListener("mousemove", dragMove);
document.addEventListener("mouseup", dragEnd);
};
const dragMove = (e) => {
const dx = e.clientX - startX;
const dy = e.clientY - startY;
const newX = initialX + dx;
const newY = initialY + dy;
const maxX = window.innerWidth - el.offsetWidth;
const maxY = window.innerHeight - el.offsetHeight;
/**边界检查 */
el.style.left = `${Math.min(Math.max(newX, 0), maxX)}px`;
el.style.top = `${Math.min(Math.max(newY, 0), maxY)}px`;
};
const dragEnd = () => {
document.removeEventListener("mousemove", dragMove);
document.removeEventListener("mouseup", dragEnd);
};
el.addEventListener("mousedown", dragStart);
},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
编辑 (opens new window)
上次更新: 2024/10/16, 05:22:08