在现代网页开发中,用户交互是一个非常重要的部分。在这篇文章中,我们将详细介绍如何使用原生 JavaScript 实现块级元素的拖拽与缩放功能。具体来说,我们将实现以下功能:
- 点击并拖动
outer
元素,可以移动整个块。 - 点击并拖动
inner
元素,可以调整outer
元素的宽高。
实现思路
为了实现上述功能,我们需要对两个元素分别进行事件监听和处理。具体来说,我们需要监听 mousedown
、mousemove
和 mouseup
事件,并根据事件触发的位置和元素的状态,来决定执行拖动还是缩放操作。
HTML 结构
首先,我们定义两个块元素 outer
和 inner
。inner
位于 outer
的右下角,用于调整 outer
的大小。
<div id="outer" style="width: 100px; height: 100px; border: 1px solid black; position: relative;">
<span id="inner" style="position: absolute; bottom: 0; right: 0; width: 10px; height: 10px; background: red; cursor: nwse-resize;"></span>
</div>
CSS 样式
简单的样式来定义块元素的尺寸和位置:
#outer {
width: 100px;
height: 100px;
border: 1px solid black;
position: relative;
}
#inner {
position: absolute;
bottom: 0;
right: 0;
width: 10px;
height: 10px;
background: red;
cursor: nwse-resize;
}
JavaScript 实现
接下来,我们编写 JavaScript 代码,实现块的拖动和缩放功能。我们需要两个主要的事件处理程序,一个用于 outer
的拖动,另一个用于 inner
的缩放。
拖动功能
首先实现 outer
的拖动功能:
document.addEventListener('DOMContentLoaded', function() {
const outer = document.getElementById('outer');
let isDragging = false;
let dragStartX, dragStartY, startLeft, startTop;
outer.addEventListener('mousedown', function(e) {
if (e.target === outer) {
isDragging = true;
dragStartX = e.clientX;
dragStartY = e.clientY;
startLeft = outer.offsetLeft;
startTop = outer.offsetTop;
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDrag);
}
});
function drag(e) {
if (isDragging) {
const dx = e.clientX - dragStartX;
const dy = e.clientY - dragStartY;
outer.style.left = `${startLeft + dx}px`;
outer.style.top = `${startTop + dy}px`;
}
}
function stopDrag() {
isDragging = false;
document.removeEventListener('mousemove', drag);
document.removeEventListener('mouseup', stopDrag);
}
});
以下是实现拖动效果,此时还未实现缩放功能。
缩放功能
接下来实现 inner
的缩放功能:
document.addEventListener('DOMContentLoaded', function() {
const outer = document.getElementById('outer');
const inner = document.getElementById('inner');
let isResizing = false;
let resizeStartX, resizeStartY, startWidth, startHeight;
inner.addEventListener('mousedown', function(e) {
e.stopPropagation(); // 阻止事件冒泡到 outer
isResizing = true;
resizeStartX = e.clientX;
resizeStartY = e.clientY;
startWidth = outer.offsetWidth;
startHeight = outer.offsetHeight;
document.addEventListener('mousemove', resize);
document.addEventListener('mouseup', stopResize);
});
function resize(e) {
if (isResizing) {
const dx = e.clientX - resizeStartX;
const dy = e.clientY - resizeStartY;
outer.style.width = `${startWidth + dx}px`;
outer.style.height = `${startHeight + dy}px`;
}
}
function stopResize() {
isResizing = false;
document.removeEventListener('mousemove', resize);
document.removeEventListener('mouseup', stopResize);
}
});
组合功能
为了确保两个功能可以同时存在,我们需要确保在 inner
被拖动时,outer
的拖动功能不会被触发。为此,我们在 inner
的 mousedown
事件处理程序中调用 e.stopPropagation()
,以阻止事件冒泡到 outer
。
完整代码
以下是完整的实现代码,包括 HTML、CSS 和 JavaScript 部分:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>拖拽与缩放功能</title>
<style>
#outer {
width: 100px;
height: 100px;
border: 1px solid black;
position: absolute;
}
#inner {
position: absolute;
bottom: 0;
right: 0;
width: 10px;
height: 10px;
background: red;
cursor: nwse-resize;
}
</style>
</head>
<body>
<div id="outer">
<span id="inner"></span>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const outer = document.getElementById('outer');
const inner = document.getElementById('inner');
let isDragging = false;
let isResizing = false;
let dragStartX, dragStartY, startLeft, startTop;
let resizeStartX, resizeStartY, startWidth, startHeight;
outer.addEventListener('mousedown', function(e) {
if (e.target === outer) {
isDragging = true;
dragStartX = e.clientX;
dragStartY = e.clientY;
startLeft = outer.offsetLeft;
startTop = outer.offsetTop;
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDrag);
}
});
inner.addEventListener('mousedown', function(e) {
e.stopPropagation(); // 阻止事件冒泡到 outer
isResizing = true;
resizeStartX = e.clientX;
resizeStartY = e.clientY;
startWidth = outer.offsetWidth;
startHeight = outer.offsetHeight;
document.addEventListener('mousemove', resize);
document.addEventListener('mouseup', stopResize);
});
function drag(e) {
if (isDragging) {
const dx = e.clientX - dragStartX;
const dy = e.clientY - dragStartY;
outer.style.left = `${startLeft + dx}px`;
outer.style.top = `${startTop + dy}px`;
}
}
function stopDrag() {
isDragging = false;
document.removeEventListener('mousemove', drag);
document.removeEventListener('mouseup', stopDrag);
}
function resize(e) {
if (isResizing) {
const dx = e.clientX - resizeStartX;
const dy = e.clientY - resizeStartY;
outer.style.width = `${startWidth + dx}px`;
outer.style.height = `${startHeight + dy}px`;
}
}
function stopResize() {
isResizing = false;
document.removeEventListener('mousemove', resize);
document.removeEventListener('mouseup', stopResize);
}
});
</script>
</body>
</html>
总结
通过本文的介绍和代码示例,我们成功实现了使用原生 JavaScript 实现块级元素的拖拽与缩放功能。在实际开发中,这种交互功能非常常见,并且对于提升用户体验非常有帮助。希望本文能够帮助你更好地理解事件处理和 DOM 操作。如果你有任何问题或建议,欢迎交流讨论。