拖拽元素组件的实现
1. 简单拖拽元素组件实现
<template>
<div
ref="box"
class="draggable-box"
:style="{ top: boxTop + 'px', left: boxLeft + 'px' }"
@mousedown="startDrag"
>
Drag Me
</div>
</template>
<script>
export default {
name: 'DraggableIndex',
data () {
return {
dragging: false,
startX: 0,
startY: 0,
boxTop: 100,
boxLeft: 100
}
},
methods: {
startDrag (event) {
this.dragging = true
this.startX = event.clientX
this.startY = event.clientY
window.addEventListener('mousemove', this.drag)
window.addEventListener('mouseup', this.endDrag)
},
drag (event) {
if (this.dragging) {
const offsetX = event.clientX - this.startX
const offsetY = event.clientY - this.startY
this.boxTop += offsetY
this.boxLeft += offsetX
this.startX = event.clientX
this.startY = event.clientY
}
},
endDrag () {
this.dragging = false
window.removeEventListener('mousemove', this.drag)
window.removeEventListener('mouseup', this.endDrag)
}
}
}
</script>
<style>
.draggable-box {
position: absolute;
background-color: #e0e0e0;
padding: 10px;
cursor: pointer;
}
</style>
2. 吸附边缘的拖拽元素组件实现
<template>
<div
ref="box"
class="draggable-box"
:style="{ top: boxTop + 'px', left: boxLeft + 'px' }"
@mousedown="startDrag"
>
Drag Me
</div>
</template>
<script>
export default {
name: 'draggableIndex',
data () {
return {
dragging: false,
startX: 0,
startY: 0,
boxTop: 100,
boxLeft: 100,
windowWidth: 0,
windowHeight: 0,
boxWidth: 0,
boxHeight: 0,
edgeThreshold: 20 // 边缘吸附阈值
}
},
mounted () {
this.windowWidth = window.innerWidth
this.windowHeight = window.innerHeight
this.boxWidth = this.$refs.box.offsetWidth
this.boxHeight = this.$refs.box.offsetHeight
},
methods: {
startDrag (event) {
this.dragging = true
this.startX = event.clientX
this.startY = event.clientY
window.addEventListener('mousemove', this.drag)
window.addEventListener('mouseup', this.endDrag)
},
drag (event) {
if (this.dragging) {
const offsetX = event.clientX - this.startX
const offsetY = event.clientY - this.startY
this.boxTop += offsetY
if (this.boxTop <= 0) {
this.boxTop = 0
} else if (this.boxTop >= this.windowHeight - this.boxHeight) {
this.boxTop = this.windowHeight - this.boxHeight
}
this.boxLeft += offsetX
if (this.boxLeft <= 0) {
this.boxLeft = 0
} else if (this.boxLeft >= this.windowWidth - this.boxWidth) {
this.boxLeft = this.windowWidth - this.boxWidth
}
this.startX = event.clientX
this.startY = event.clientY
}
},
endDrag () {
this.dragging = false
window.removeEventListener('mousemove', this.drag)
window.removeEventListener('mouseup', this.endDrag)
}
}
}
</script>
<style>
.draggable-box {
position: absolute;
background-color: #e0e0e0;
padding: 10px;
cursor: pointer;
}
</style>
3. 实现可拖拽缩放的元素
步骤一:布局实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="./index.css" />
</head>
<body>
<div class="box" id="drag">
<div class="resize-handle top-left"></div>
<div class="resize-handle top"></div>
<div class="resize-handle top-right"></div>
<div class="resize-handle right"></div>
<div class="resize-handle bottom-right"></div>
<div class="resize-handle bottom"></div>
<div class="resize-handle bottom-left"></div>
<div class="resize-handle left"></div>
</div>
</body>
<script src="./index.js"></script>
</html>
步骤二:样式添加
.box {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
background-color: #f0f0f0;
cursor: move;
}
.resize-handle {
position: absolute;
width: 10px;
height: 10px;
background-color: #000;
}
.top-left {
top: -5px;
left: -5px;
cursor: nw-resize;
}
.top {
top: -5px;
left: calc(50% - 5px);
cursor: ns-resize;
}
.top-right {
top: -5px;
right: -5px;
cursor: ne-resize;
}
.right {
top: calc(50% - 5px);
right: -5px;
cursor: ew-resize;
}
.bottom-right {
bottom: -5px;
right: -5px;
cursor: se-resize;
}
.bottom {
bottom: -5px;
left: calc(50% - 5px);
cursor: ns-resize;
}
.bottom-left {
bottom: -5px;
left: -5px;
cursor: sw-resize;
}
.left {
top: calc(50% - 5px);
left: -5px;
cursor: ew-resize;
}
步骤三:拖拽和缩放功能逻辑实现
const dragElement = document.getElementById("drag");
// 拖拽功能
dragElement.addEventListener("mousedown", startDrag);
function startDrag(event) {
event.preventDefault();
const currentHandle = event.target;
const isResizeHandle = currentHandle.className.includes("resize-handle");
if (isResizeHandle) return;
const startX = event.clientX;
const startY = event.clientY;
const startLeft = dragElement.offsetLeft;
const startTop = dragElement.offsetTop;
document.addEventListener("mousemove", drag);
document.addEventListener("mouseup", stopDrag);
function drag(event) {
const dx = event.clientX - startX;
const dy = event.clientY - startY;
const newLeft = startLeft + dx;
const newTop = startTop + dy;
dragElement.style.left = newLeft + "px";
dragElement.style.top = newTop + "px";
}
function stopDrag() {
document.removeEventListener("mousemove", drag);
document.removeEventListener("mouseup", stopDrag);
}
}
// 缩放功能
const resizeHandles = document.getElementsByClassName("resize-handle");
Array.from(resizeHandles).forEach((handle) => {
handle.addEventListener("mousedown", startResize);
});
function startResize(event) {
event.preventDefault();
const currentHandle = event.target;
const direction = currentHandle.className.split(" ")[1];
const startX = event.clientX;
const startY = event.clientY;
const startWidth = dragElement.offsetWidth;
const startHeight = dragElement.offsetHeight;
const startLeft = dragElement.offsetLeft;
const startTop = dragElement.offsetTop;
document.addEventListener("mousemove", resize);
document.addEventListener("mouseup", stopResize);
function resize(event) {
const dx = event.clientX - startX;
const dy = event.clientY - startY;
let width = startWidth,
height = startHeight,
left = startLeft,
top = startTop;
if (direction.includes("left")) {
width = startWidth - dx + "px";
left = startLeft + dx / 2 + "px";
}
if (direction.includes("right")) {
width = startWidth + dx + "px";
left = startLeft + dx / 2 + "px";
}
if (direction.includes("top")) {
height = startHeight - dy + "px";
top = startTop + dy / 2 + "px";
}
if (direction.includes("bottom")) {
height = startHeight + dy + "px";
top = startTop + dy / 2 + "px";
}
if (parseInt(width) <= 0 || parseInt(height) <= 0) return;
dragElement.style.width = width;
dragElement.style.height = height;
dragElement.style.left = left;
dragElement.style.top = top;
}
function stopResize() {
document.removeEventListener("mousemove", resize);
document.removeEventListener("mouseup", stopResize);
}
}
步骤四:拖拽和缩放功能实现思路
拖拽功能
我们需要鼠标在div内按下不松开的时候,div可以跟着鼠标的位置移动,这里我们可以从鼠标的三种事件的触发来入手:
- 1、鼠标按下(mousedown)
首先我们需要监听鼠标按下事件。
const dragElement = document.getElementById("drag");
dragElement.addEventListener("mousedown", startDrag);
判断点击事件是否为锚点触发,是的话则不执行拖拽逻辑。这里我们可以通过样式名来判断,锚点我们都给它加上了resize-handle
,我们只需要判断样式名是否包含resize-handle
就可以。
function startDrag(event) {
event.preventDefault();
const currentHandle = event.target;
const isResizeHandle = currentHandle.className.includes("resize-handle");
if (isResizeHandle) return;
}
记录下鼠标点击的坐标及拖拽元素所在位置,用于后面计算鼠标移动距离和对拖拽元素进行移动,监听鼠标移动和抬起事件
const startX = event.clientX;
const startY = event.clientY;
const startLeft = dragElement.offsetLeft;
const startTop = dragElement.offsetTop;
document.addEventListener("mousemove", drag);
document.addEventListener("mouseup", stopDrag);
- 2、鼠标移动(mousemove)
鼠标移动的时候计算鼠标当前位置与鼠标点击位置的相对距离,将拖拽元素的位置也移动相应的相对距离
function drag(event) {
const dx = event.clientX - startX;
const dy = event.clientY - startY;
const newLeft = startLeft + dx;
const newTop = startTop + dy;
dragElement.style.left = newLeft + "px";
dragElement.style.top = newTop + "px";
}
- 3、鼠标抬起(mouseup)
鼠标抬起的时候将鼠标移动和鼠标抬起的监听事件移除。
function stopDrag() {
document.removeEventListener("mousemove", drag);
document.removeEventListener("mouseup", stopDrag);
}
到这里我们就完成了一个最基本的可拖拽元素了,接下来就该来实现缩放功能了。
缩放功能
我们希望在点击缩放锚点进行移动的时候,元素会随着鼠标继续缩小或放大,这里我们仍然是要从鼠标触发的三种事件来入手:
- 1、鼠标按下(mousedown)
我们需要监听所有锚点的鼠标按下事件,首先我们需要先获取所有的锚点元素:
const resizeHandles = document.getElementsByClassName("resize-handle");
再监听所有锚点元素的鼠标按下事件:
Array.from(resizeHandles).forEach((handle) => {
handle.addEventListener("mousedown", startResize);
});
记录鼠标按下的初始位置及缩放元素的初始位置和宽高,便于后面对缩放元素进行缩放操作,并为缩放元素加上鼠标移动和鼠标抬起的监听事件。
function startResize(event) {
event.preventDefault();
const currentHandle = event.target;
const direction = currentHandle.className.split(" ")[1];
startX = event.clientX;
startY = event.clientY;
startWidth = dragElement.offsetWidth;
startHeight = dragElement.offsetHeight;
startLeft = dragElement.offsetLeft;
startTop = dragElement.offsetTop;
document.addEventListener("mousemove", resize);
document.addEventListener("mouseup", stopResize);
}
- 2、鼠标移动(mousemove)
鼠标移动的时候我们需要判断当前是从哪个锚点触发的缩放事件,我们可以从锚点的样式名className
来做区分。
const currentHandle = event.target;
const direction = currentHandle.className.split(" ")[1];
不同锚点我们需要对元素进行不同的操作,我们可以分为四个方位来进行判断并区分操作:
(1)左边
判断样式名是否包含left
,左边锚点会触发元素的宽度变化及左右位置的变化,这时候鼠标左移相对于元素来说是放大,右移相对于元素来说是缩小,所以元素的宽度应该减去鼠标的位移距离。
if (direction.includes("left")) {
width = startWidth - dx + "px";
left = startLeft + dx / 2 + "px";
}
(2)右边
判断样式名是否包含right
,右边锚点会触发元素的宽度变化及左右位置的变化,这时候鼠标左移相对于元素来说是缩小,右移相对于元素来说是放大,所以元素的宽度应该加上鼠标的位移距离。
if (direction.includes("right")) {
width = startWidth + dx + "px";
left = startLeft + dx / 2 + "px";
}
(3)上边
判断样式名是否包含top
,上边锚点会触发元素的高度变化及上下位置的变化,这时候鼠标上移相对于元素来说是放大,下移相对于元素来说是缩小,所以元素的高度应该减去鼠标的位移距离。
if (direction.includes("top")) {
height = startHeight - dy + "px";
top = startTop + dy / 2 + "px";
}
(4)下边
判断样式名是否包含bottom
,下边锚点会触发元素的高度变化及上下位置的变化,这时候鼠标上移相对于元素来说是缩小,下移相对于元素来说是放大,所以元素的高度应该加上鼠标的位移距离。
if (direction.includes("bottom")) {
height = startHeight + dy + "px";
top = startTop + dy / 2 + "px";
}
我们还需要判断当前元素的宽度和高度是否小于等于0,等于0的时候我们不再对其进行缩放操作,大于0则对元素进行赋值操作。
if (parseInt(width) <= 0 || parseInt(height) <= 0) return;
dragElement.style.width = width;
dragElement.style.height = height;
dragElement.style.left = left;
dragElement.style.top = top;
完整代码如下:
function resize(event) {
const dx = event.clientX - startX;
const dy = event.clientY - startY;
let width = startWidth,
height = startHeight,
left = startLeft,
top = startTop;
if (direction.includes("left")) {
width = startWidth - dx + "px";
left = startLeft + dx / 2 + "px";
}
if (direction.includes("right")) {
width = startWidth + dx + "px";
left = startLeft + dx / 2 + "px";
}
if (direction.includes("top")) {
height = startHeight - dy + "px";
top = startTop + dy / 2 + "px";
}
if (direction.includes("bottom")) {
height = startHeight + dy + "px";
top = startTop + dy / 2 + "px";
}
if (parseInt(width) <= 0 || parseInt(height) <= 0) return;
dragElement.style.width = width;
dragElement.style.height = height;
dragElement.style.left = left;
dragElement.style.top = top;
}
- 3、鼠标抬起(mouseup)
鼠标抬起的时候将鼠标移动和鼠标抬起的监听事件移除。
function stopResize() {
document.removeEventListener("mousemove", resize);
document.removeEventListener("mouseup", stopResize);
}
到这里我们就完成了一个最基本的可拖拽缩放的元素了。