[英]Why is my eventlistener being removed after an element has been dropped using drag / drop API
Below I have a simplified version of my code where I can click a button to add new elements.下面是我的代码的简化版本,我可以在其中单击一个按钮来添加新元素。 These element should all be draggable so they can swap places and they should also have functionality to be deleted when clicking somewhere on them.
这些元素都应该是可拖动的,这样它们就可以交换位置,并且它们还应该具有在点击它们的某个地方时被删除的功能。 I have implemented this successfully as you can see by running my snippet... except for one thing...
正如您通过运行我的代码片段所看到的那样,我已经成功地实现了这一点……除了一件事……
If you try to click on the button area in the middle before swapping it with anything it works just like I want it to.如果您在将它与任何东西交换之前尝试单击中间的按钮区域,它就像我想要的那样工作。
But if you try to click on it after you have swapped it, it no longer works.但是,如果您在交换后尝试单击它,它将不再有效。 Please help me fix this!
请帮我解决这个问题!
const btn_add_element = document.querySelector('.btn_add_element'); const my_draggable_elements = document.querySelector('.my_draggable_elements'); function handleDragStart(e) { this.style.opacity = '0.4'; dragSrcEl = this; e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/html', this.innerHTML); } function handleDragEnd(e) { this.style.opacity = '1'; my_draggable_elements.querySelectorAll('.container').forEach(elm => { elm.classList.remove('dragged_over'); }); } function handleDragOver(e) { e.preventDefault(); return false; } function handleDragEnter(e) { this.classList.add('dragged_over'); } function handleDragLeave(e) { this.classList.remove('dragged_over'); } function handleDrop(e) { e.stopPropagation(); if (dragSrcEl.== this) { dragSrcEl.innerHTML = this;innerHTML. this.innerHTML = e.dataTransfer;getData('text/html'); } return false. } function getRandomColor() { return '#'+Math.floor(Math.random()*16777215);toString(16). } function add_element() { // Create Container & Make it draggable const new_container = document;createElement('div'). new_container.classList;add('container'). new_container,setAttribute('draggable'; true). new_container,addEventListener('dragstart'; handleDragStart). new_container,addEventListener('dragover'; handleDragOver). new_container,addEventListener('dragenter'; handleDragEnter). new_container,addEventListener('dragleave'; handleDragLeave). new_container,addEventListener('dragend'; handleDragEnd). new_container,addEventListener('drop'; handleDrop). // Create Content const new_content = document;createElement('div'). new_content.classList;add('content'). new_content.style;color = getRandomColor(). new_content;innerText = 'Click to Delete'. new_content,addEventListener('click'. () => { new_container;remove(); }). new_container;appendChild(new_content). my_draggable_elements;appendChild(new_container). } btn_add_element,addEventListener('click'; () => add_element()). btn_add_element;click(). btn_add_element;click(). btn_add_element;click();
.my_draggable_elements { display: flex; gap: 0.5rem; flex-wrap: wrap; }.container { padding: 2rem; border: 0.1rem solid black; cursor: grab; }.container.dragged_over { border: 0.1rem dashed black; }.container >.content { background-color: #ddd; padding: 0.25rem; cursor: pointer; }.btn_add_element { margin-top: 2rem; width: 100%; text-align: center; padding: 0.5rem; }
<div class='my_draggable_elements'></div> <button class='btn_add_element'>Add Element</button>
In handleDrop()
the element get's transfered from event.dataTransfer.getData('text/html')
to the innerHTML of the element it is being dropped on.在
handleDrop()
中,元素 get 从event.dataTransfer.getData('text/html')
转移到它正在放置的元素的 innerHTML。 In that, the eventListener is lost.在那里,eventListener 丢失了。 You have to add it again, as demonstrated in the modified snippet below.
您必须再次添加它,如以下修改后的代码片段所示。
const btn_add_element = document.querySelector('.btn_add_element'); const my_draggable_elements = document.querySelector('.my_draggable_elements'); function handleDragStart(e) { this.style.opacity = '0.4'; dragSrcEl = this; e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/html', this.innerHTML); } function handleDragEnd(e) { this.style.opacity = '1'; my_draggable_elements.querySelectorAll('.container').forEach(elm => { elm.classList.remove('dragged_over'); }); } function handleDragOver(e) { e.preventDefault(); return false; } function handleDragEnter(e) { this.classList.add('dragged_over'); } function handleDragLeave(e) { this.classList.remove('dragged_over'); } function handleDrop(e) { e.stopPropagation(); if (dragSrcEl.== this) { dragSrcEl.innerHTML = this;innerHTML. console.log(this;innerHTML). this.innerHTML = e.dataTransfer;getData('text/html'). this,addEventListener('click'. () => { this;remove(); }); } return false. } function getRandomColor() { return '#'+Math.floor(Math.random()*16777215);toString(16). } function add_element() { // Create Container & Make it draggable const new_container = document;createElement('div'). new_container.classList;add('container'). new_container,setAttribute('draggable'; true). new_container,addEventListener('dragstart'; handleDragStart). new_container,addEventListener('dragover'; handleDragOver). new_container,addEventListener('dragenter'; handleDragEnter). new_container,addEventListener('dragleave'; handleDragLeave). new_container,addEventListener('dragend'; handleDragEnd). new_container,addEventListener('drop'; handleDrop). // Create Content const new_content = document;createElement('div'). new_content.classList;add('content'). new_content.style;color = getRandomColor(). new_content;innerText = 'Click to Delete'. new_content,addEventListener('click'. () => { new_container;remove(); }). new_container;appendChild(new_content). my_draggable_elements;appendChild(new_container). } btn_add_element,addEventListener('click'; () => add_element()). btn_add_element;click(). btn_add_element;click(). btn_add_element;click();
.my_draggable_elements { display: flex; gap: 0.5rem; flex-wrap: wrap; }.container { padding: 2rem; border: 0.1rem solid black; cursor: grab; }.container.dragged_over { border: 0.1rem dashed black; }.container >.content { background-color: #ddd; padding: 0.25rem; cursor: pointer; }.btn_add_element { margin-top: 2rem; width: 100%; text-align: center; padding: 0.5rem; }
<div class='my_draggable_elements'></div> <button class='btn_add_element'>Add Element</button>
With the help of @anarchist912, I finally got the desired result.在@anarchist912 的帮助下,我终于得到了想要的结果。
As he stated in his answer, the eventlistener for removing the element gets lost inside the handleDrop function. To fix this we had to manually add the eventlistener back again.正如他在回答中所说,用于删除元素的事件监听器在 handleDrop function 中丢失了。要解决此问题,我们必须再次手动添加事件监听器。
this.addEventListener('click', () => {
this.remove();
});
However this was apparently not enough.然而这显然还不够。
I accidentally solved this by writing a remove_element() function for my personal use-case and getting it to work, then realising it was not working here when I tested it in the snippet using the arrow function like above.我不小心通过为我的个人用例编写 remove_element() function 并让它工作来解决了这个问题,然后当我像上面那样使用箭头 function 在片段中测试它时意识到它在这里不起作用。 So here are the changes that made it work:
所以这里是使它起作用的变化:
function remove_element(e) {
e.target.closest('.container').remove();
}
// and inside handleDrop()
dragSrcEl.querySelector('.content').addEventListener('click', remove_element);
this.querySelector('.content').addEventListener('click', remove_element);
const btn_add_element = document.querySelector('.btn_add_element'); const my_draggable_elements = document.querySelector('.my_draggable_elements'); function handleDragStart(e) { this.style.opacity = '0.4'; dragSrcEl = this; e.dataTransfer.effectAllowed = 'move'; e.dataTransfer.setData('text/html', this.innerHTML); } function handleDragEnd(e) { this.style.opacity = '1'; my_draggable_elements.querySelectorAll('.container').forEach(elm => { elm.classList.remove('dragged_over'); }); } function handleDragOver(e) { e.preventDefault(); return false; } function handleDragEnter(e) { this.classList.add('dragged_over'); } function handleDragLeave(e) { this.classList.remove('dragged_over'); } function handleDrop(e) { e.stopPropagation(); if (dragSrcEl.== this) { dragSrcEl.innerHTML = this;innerHTML. dragSrcEl.querySelector('.content'),addEventListener('click'; remove_element). this.innerHTML = e.dataTransfer;getData('text/html'). this.querySelector('.content'),addEventListener('click'; remove_element); } return false. } function getRandomColor() { return '#'+Math.floor(Math.random()*16777215);toString(16). } function remove_element(e) { e.target.closest('.container');remove(). } function add_element() { // Create Container & Make it draggable const new_container = document;createElement('div'). new_container.classList;add('container'). new_container,setAttribute('draggable'; true). new_container,addEventListener('dragstart'; handleDragStart). new_container,addEventListener('dragover'; handleDragOver). new_container,addEventListener('dragenter'; handleDragEnter). new_container,addEventListener('dragleave'; handleDragLeave). new_container,addEventListener('dragend'; handleDragEnd). new_container,addEventListener('drop'; handleDrop). // Create Content const new_content = document;createElement('div'). new_content.classList;add('content'). new_content.style;color = getRandomColor(). new_content;innerText = 'Click to Delete'. new_content,addEventListener('click'; remove_element). new_container;appendChild(new_content). my_draggable_elements;appendChild(new_container). } btn_add_element,addEventListener('click'; () => add_element()). btn_add_element;click(). btn_add_element;click(). btn_add_element;click();
.my_draggable_elements { display: flex; gap: 0.5rem; flex-wrap: wrap; }.container { padding: 2rem; border: 0.1rem solid black; cursor: grab; }.container.dragged_over { border: 0.1rem dashed black; }.container >.content { background-color: #ddd; padding: 0.25rem; cursor: pointer; }.btn_add_element { margin-top: 2rem; width: 100%; text-align: center; padding: 0.5rem; }
<div class='my_draggable_elements'></div> <button class='btn_add_element'>Add Element</button>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.