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

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

我有一个使用 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>
javascript drag-and-drop
1个回答
1
投票

这不是问题。在这里,我将事件监听器添加到无序列表中 (

<ul>
)。因此,添加、克隆和删除列表项 (
<li>
) 不是问题。

使用

insertAdjacentHTML()
之类的方法是没有问题的。在此示例中,我仅使用
cloneNode()
克隆移动的节点,然后使用
insertBefore()
将克隆的节点插入到悬停/放置的列表项之前。

const activities = [{
    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(activities);
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>

© www.soinside.com 2019 - 2024. All rights reserved.