我拖动元素,当它们重叠时,它们不会发送服务器消息(通过网络检查)。
用户界面没有任何故障。
我对这个问题没有太多细节,这就是我所知道的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Element Combiner</title>
<style>
</style>
</head>
<body>
<div id="sidebar">
<div class="draggable" id="fire" draggable="true">🔥 Fire</div>
<div class="draggable" id="earth" draggable="true">🌍 Earth</div>
<div class="draggable" id="water" draggable="true">💧 Water</div>
<div class="draggable" id="wind" draggable="true">🌬️ Wind</div>
</div>
<div id="drop-area"></div>
<script>
let draggedElement = null;
let offsetX = 0, offsetY = 0;
document.querySelectorAll('.draggable').forEach(item => {
item.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', e.target.id);
draggedElement = e.target.cloneNode(true);
draggedElement.style.position = 'absolute';
draggedElement.style.zIndex = 100;
const rect = e.target.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
document.body.appendChild(draggedElement);
draggedElement.style.left = `${e.clientX - offsetX}px`;
draggedElement.style.top = `${e.clientY - offsetY}px`;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
});
function onMouseMove(event) {
if (draggedElement) {
draggedElement.style.left = `${event.clientX - offsetX}px`;
draggedElement.style.top = `${event.clientY - offsetY}px`;
}
}
function onMouseUp(event) {
if (draggedElement) {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
const dropArea = document.getElementById('drop-area');
const dropRect = dropArea.getBoundingClientRect();
const elRect = draggedElement.getBoundingClientRect();
if (elRect.left < dropRect.right &&
elRect.right > dropRect.left &&
elRect.top < dropRect.bottom &&
elRect.bottom > dropRect.top) {
const dropTarget = draggedElement.cloneNode(true);
dropTarget.classList.remove('draggable');
dropTarget.classList.add('drop-target');
dropTarget.style.position = 'absolute';
dropTarget.style.left = `${event.clientX - dropArea.getBoundingClientRect().left - offsetX}px`;
dropTarget.style.top = `${event.clientY - dropArea.getBoundingClientRect().top - offsetY}px`;
dropArea.appendChild(dropTarget);
makeDraggable(dropTarget);
}
document.body.removeChild(draggedElement);
draggedElement = null;
}
}
function makeDraggable(element) {
element.addEventListener('mousedown', (e) => {
const rect = element.getBoundingClientRect();
const offsetX = e.clientX - rect.left;
const offsetY = e.clientY - rect.top;
function moveAt(x, y) {
element.style.left = `${x - offsetX}px`;
element.style.top = `${y - offsetY}px`;
}
function onMouseMove(event) {
moveAt(event.clientX, event.clientY);
}
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', () => {
document.removeEventListener('mousemove', onMouseMove);
}, { once: true });
});
}
</script>
</body>
</html>
我尝试了一些方法来查看哪部分不起作用,服务器很好,只是组合功能的元素不起作用。
有很多东西要涵盖。这里有几点:
sidebar.addEventListener('dragstart', e => {});
。e.target
并不总是您期望的元素。在拖放区域中,如果您将其拖放到另一个项目上,该项目就是 e.target
,而不是 #drop-area
。因此,使用 e.target.closest('#drop-area')
来查找元素。e.dataTransfer
获取有关被拖动项目的数据,包括鼠标相对于被拖动项目的位置。在示例中,您可以从侧边栏和放置区域开始拖动,因此有两个事件侦听器
dragstart
。请注意,每种情况下发送的数据之间存在差异。然后在 drop
回调中,我根据“类型”(id 或名称)执行两件不同的事情。
const sidebar = document.getElementById('sidebar');
const drop_area = document.getElementById('drop-area');
sidebar.addEventListener('dragstart', e => {
let sidebar = e.target.closest('#sidebar');
let item = e.target.closest('.draggable');
let data = {
x: e.clientX - item.offsetLeft - sidebar.offsetLeft,
y: e.clientY - item.offsetTop - sidebar.offsetTop,
name: item.dataset.name
};
e.dataTransfer.setData('text/plain', JSON.stringify(data));
});
drop_area.addEventListener('dragstart', e => {
let drop_area = e.target.closest('#drop-area');
let item = e.target.closest('.draggable');
let data = {
x: e.clientX - item.offsetLeft - drop_area.offsetLeft,
y: e.clientY - item.offsetTop - drop_area.offsetTop,
id: item.dataset.id
};
e.dataTransfer.setData('text/plain', JSON.stringify(data));
});
drop_area.addEventListener('dragover', e => {
e.preventDefault();
let drop_area = e.target.closest('#drop-area');
drop_area.classList.add('dragover');
});
drop_area.addEventListener('drop', e => {
e.preventDefault();
let drop_area = e.target.closest('#drop-area');
drop_area.classList.remove('dragover');
let data = JSON.parse(e.dataTransfer.getData('text/plain'));
let type = (data.id) ? 'id' : 'name';
if(type == 'name'){
let item = sidebar.querySelector(`div[data-name="${data.name}"]`);
let clone = item.cloneNode(true);
clone.style.left = (e.clientX - drop_area.offsetLeft - data.x) + 'px';
clone.style.top = (e.clientY - drop_area.offsetTop - data.y) + 'px';
drop_area.append(clone);
}else if(type == 'id'){
let item = drop_area.querySelector(`div[data-id="${data.id}"]`);
item.style.left = (e.clientX - drop_area.offsetLeft - data.x) + 'px';
item.style.top = (e.clientY - drop_area.offsetTop - data.y) + 'px';
}
drop_area.querySelectorAll('.draggable').forEach((item, i) => item.dataset.id = i);
});
body {
display: flex;
gap: 2em;
}
#sidebar {
position: relative;
}
#drop-area {
border: solid black thin;
width: 400px;
min-height: 200px;
position: relative;
}
#drop-area.dragover {
background-color: #eee;
}
#drop-area .draggable {
position: absolute;
display: inline;
}
<div id="sidebar">
<div class="draggable" data-name="fire" draggable="true">🔥 Fire</div>
<div class="draggable" data-name="earth" draggable="true">🌍 Earth</div>
<div class="draggable" data-name="water" draggable="true">💧 Water</div>
<div class="draggable" data-name="wind" draggable="true">🌬️ Wind</div>
</div>
<div id="drop-area"></div>