我有一个使用 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>
这不是问题。在这里,我将事件监听器添加到无序列表中 (
<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>