为什么使用拖放 API 删除元素后,我的 eventlistener 被删除

Why is my eventlistener being removed after an element has been dropped using drag / drop API

提问人:Oscar R 提问时间:2/1/2023 更新时间:2/1/2023 访问量:51

问:

下面我有一个简化版本的代码,我可以在其中单击按钮来添加新元素。这些元素都应该是可拖动的,这样它们就可以交换位置,并且它们还应该具有在单击它们的位置时要删除的功能。我已经成功地实现了这一点,正如你通过运行我的片段所看到的......除了一件事......

如果您尝试在将它换成任何东西之前单击中间的按钮区域,它就像我想要的那样工作。

但是,如果您在交换它后尝试单击它,它将不再起作用。请帮我解决这个问题!

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>

JavaScript 拖放 AddEventListener 可拖动

评论


答:

1赞 Wu Wei 2/1/2023 #1

在元素中,get's transfer from to the innerHTML of the element is placed to the element of the element is placed to the element of the element gets transfer to the element of the element is stored to the element在这种情况下,eventListener 丢失了。您必须再次添加它,如下面修改后的代码片段所示。handleDrop()event.dataTransfer.getData('text/html')

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>

评论

0赞 Oscar R 2/1/2023
在我修改了它以将事件侦听器添加到 drop 函数中的 dragSrcEl 之后,我让它工作了,谢谢!
1赞 Wu Wei 2/1/2023
是的,但尝试多次拖动。有些东西还没有起作用。在某些时候,一个元素将删除自身和另一个元素,而第三个元素将不再具有 eventListener。
0赞 Oscar R 2/1/2023
我想通了。问题是我们在handleDrop函数中将eventlistener添加到容器元素本身,而它应该附加到content元素。将代码更改为 this.querySelector('.content').addEventListener( ... ) 后我让它工作了
0赞 Oscar R 2/1/2023
我意识到还有另一个缺失的部分可以使它工作,但现在终于,它应该可以完全工作。我做了所有的修改,都做出了回答。谢谢你的帮助。
1赞 Oscar R 2/1/2023 #2

在@anarchist912的帮助下,我终于得到了想要的结果。

正如他在回答中所说,用于删除元素的事件侦听器在 handleDrop 函数中丢失。为了解决这个问题,我们必须再次手动添加 eventlistener。

this.addEventListener('click', () => {
  this.remove();
});

然而,这显然是不够的。

我不小心解决了这个问题,为我的个人用例编写了一个 remove_element() 函数并让它工作,然后当我使用上面的箭头函数在代码段中测试它时意识到它在这里不起作用。因此,以下是使其起作用的更改:

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>