在现代网页开发中,用户交互是一个非常重要的部分。在这篇文章中,我们将详细介绍如何使用原生 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(); // 阻止事件冒泡到 outerisResizing = 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(); // 阻止事件冒泡到 outerisResizing = 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 操作。如果你有任何问题或建议,欢迎交流讨论。