为什么拖放处理不起作用?

问题描述 投票:0回答:1

我拖动元素,当它们重叠时,它们不会发送服务器消息(通过网络检查)。

用户界面没有任何故障。

我对这个问题没有太多细节,这就是我所知道的。

<!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>

我尝试了一些方法来查看哪部分不起作用,服务器很好,只是组合功能的元素不起作用。

javascript html drag-and-drop
1个回答
0
投票

有很多东西要涵盖。这里有几点:

  1. 您可以使用事件委托,而不是为每个可拖动项目分配事件侦听器,例如
    sidebar.addEventListener('dragstart', e => {});
  2. e.target
    并不总是您期望的元素。在拖放区域中,如果您将其拖放到另一个项目上,该项目就是
    e.target
    ,而不是
    #drop-area
    。因此,使用
    e.target.closest('#drop-area')
    来查找元素。
  3. 使用
    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>

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.