javascript 拖放在动态创建的列表上不起作用

vwhgwdsa  于 2023-06-04  发布在  Java
关注(0)|答案(1)|浏览(142)

我有一个活动列表,它是用JavaScript动态生成的,方式如下:

const renderList = (activities) => {
  const display = document.getElementById('task-list-display');
  activities.forEach((activity) => {
    console.log(activity);
    display.insertAdjacentHTML('beforeend', ` 
    <li class="task-item draggable" draggable="true">
      <div class="chk-descr">
        <input data-a1="${activity.index}" type="checkbox" name="completed"/>
        <p data-b1="${activity.index}" class="description" contenteditable="true">${activity.description}</p>
      </div>
    </li> 
    `);

我想让它的响应方式,可以使用拖放重新安排的项目。然而,我无法使这一工作。之前我设计了同样的应用程序,但不是使用insertAdjacentHTML()插入列表中的项目,而是使用createElement()创建每个元素,然后使用appendChild()将其附加到相应的HTML元素中。该应用程序上的拖放功能完全正常。我的问题是:有什么原因可以解释为什么拖放不能使用insertAdjacentHTML?动态生成的列表。
下面是所有相关代码:

let activities = [];

const dragstart = (element) => {
  element.classList.add('skateover');
};

const dragover = (element, e) => {
  e.preventDefault();
  element.classList.add('dragover');
};

const dragleave = (element) => {
  element.classList.remove('dragover');
};

const drop = (element) => {
  const skateover = document.querySelector('.skateover');
  element.before(skateover);

  repopulateList();
  element.classList.remove('dragover');
};

const dragend = (element) => {
  element.classList.remove('skateover');
};

const repopulateList = () => {
  const listItems = document.querySelectorAll('.draggable');
  emptyList();

  let i = 0;
  listItems.forEach((listItem) => {
    listItem.setAttribute('activity', i);
    i += 1;
    
    const description = listItem.getElementsByClassName('description')[0].textContent;
    const completed = listItem.getElementsByClassName('completed')[0].checked;
    const index = listItem.getAttribute('activity');

    inputActivity(description, completed, index);
  });
};

const inputActivity = (description, completed, index) => {
  activities.push({ description, completed, index: parseInt(index, 10) });
};

在HTML文件中:

<ul id="task-list-display"></ul>
5t7ly7z5

5t7ly7z51#

这不是问题。这里我将eventlistener添加到无序列表(<ul>)。因此,添加、克隆和删除列表项(<li>)不是问题。
使用像insertAdjacentHTML()这样的方法没有问题。在这个例子中,我只使用cloneNode()克隆移动的节点,然后使用insertBefore()将克隆的节点插入到悬停/放置的列表项之前。

const aktivities = [{
    index: 1,
    description: "Item 1"
  },
  {
    index: 2,
    description: "Item 2"
  },
  {
    index: 3,
    description: "Item 3"
  }
];

const display = document.getElementById('task-list-display');

const renderList = (activities) => {
  activities.forEach((activity) => {
    display.insertAdjacentHTML('beforeend', ` 
    <li class="task-item draggable" draggable="true" data-id="${activity.index}">
      <div class="chk-descr">
        <input data-a1="${activity.index}" type="checkbox" name="completed"/>
        <p data-b1="${activity.index}" class="description" contenteditable="true">${activity.description}</p>
      </div>
    </li> 
    `)
  });
};

display.addEventListener("dragstart", e => {
  e.dataTransfer.setData("text/plain", e.target.dataset.id);
});

display.addEventListener("dragover", e => {
  e.preventDefault();
  [...display.querySelectorAll('li')].forEach(li => li.classList.remove('over'));
  e.target.closest('li.task-item').classList.add('over');
});

display.addEventListener("drop", e => {
  e.preventDefault();
  [...display.querySelectorAll('li')].forEach(li => li.classList.remove('over'));
  let original = document.querySelector(`li[data-id="${e.dataTransfer.getData("text/plain")}"]`);
  let clone = original.cloneNode(true);
  let target = e.target.closest('li.task-item');
  display.insertBefore(clone, target);
  display.removeChild(original);
});

renderList(aktivities);
ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

li div {
  display: flex;
  flex-direction: row;
}

.over {
  border-top: solid thin black;
}
<ul id="task-list-display"></ul>

相关问题