错误Node.insertBefore:参数1不是对象,用于拖放新创建的待办事项



我正在处理这个todo应用程序挑战,每当添加新的todo时,我的拖放设置都会出现上述错误。它可以很好地处理已经存在的项,但一旦创建了新的todo项,代码就会中断。

const todoList = document.querySelector(".todos");
const draggables = document.querySelectorAll(".todos__item");
<ul class="todos">
<li class="todos__item todo-style" draggable="true">
<button
class="todos__complete btn"
aria-label="complete todo"
></button>
<p class="todos__text">Create your own todos so you won't forget</p>
<button class="todos__delete" aria-label="delete todo">
<img
class="todos__delete__img"
src="assets/icon-cross.svg"
alt="an icon with the symbol x that will allow you to delete the selected todo "
/>
</button>
</li>
<li class="todos__item todo-style" draggable="true">
<button
class="todos__complete btn"
aria-label="complete todo"
></button>
<p class="todos__text">
Mark as complete by pressing the left circle
</p>
<button class="todos__delete" aria-label="delete todo">
<img
class="todos__delete__img"
src="assets/icon-cross.svg"
alt="an icon with the symbol x that will allow you to delete the selected todo "
/>
</button>
</li>
<li class="todos__item todo-style" draggable="true">
<button
class="todos__complete btn"
aria-label="complete todo"
></button>
<p class="todos__text">
Or delete a todo by pressing the right X mark
</p>
<button class="todos__delete" aria-label="delete todo">
<img
class="todos__delete__img"
src="assets/icon-cross.svg"
alt="an icon with the symbol x that will allow you to delete the selected todo "
/>
</button>
</li>
<li class="todos__item todo-style" draggable="true">
<button
class="todos__complete btn"
aria-label="complete todo"
></button>
<p class="todos__text">
You can filter 'All', 'Active' and 'Completed' todos below
</p>
<button class="todos__delete" aria-label="delete todo">
<img
class="todos__delete__img"
src="assets/icon-cross.svg"
alt="an icon with the symbol x that will allow you to delete the selected todo "
/>
</button>
</li>
<li class="todos__item todo-style" draggable="true">
<button
class="todos__complete btn"
aria-label="complete todo"
></button>
<p class="todos__text">Search for todos by typing in the box above</p>
<button class="todos__delete" aria-label="delete todo">
<img
class="todos__delete__img"
src="assets/icon-cross.svg"
alt="an icon with the symbol x that will allow you to delete the selected todo "
/>
</button>
</li>
<li class="todos__item todo-style" draggable="true">
<button
class="todos__complete btn"
aria-label="complete todo"
></button>
<p class="todos__text">
Toggle between light and dark mode, by pressing the sun/moon icon
above
</p>
<button class="todos__delete" aria-label="delete todo">
<img
class="todos__delete__img"
src="assets/icon-cross.svg"
alt="an icon with the symbol x that will allow you to delete the selected todo "
/>
</button>
</li>
<li class="todos__item todo-style" draggable="true">
<button
class="todos__complete btn"
aria-label="complete todo"
></button>
<p class="todos__text">
Drag and drop todo items, to re-position them
</p>
<button class="todos__delete" aria-label="delete todo">
<img
class="todos__delete__img"
src="assets/icon-cross.svg"
alt="an icon with the symbol x that will allow you to delete the selected todo "
/>
</button>
</li>
</ul>
draggables.forEach((item) => {
item.addEventListener("dragstart", () => {
item.classList.add("dragging");
});
item.addEventListener("dragend", () => {
item.classList.remove("dragging");
});
});
todoList.addEventListener("dragover", (e) => {
e.preventDefault();
const afterElement = positionDraggableElement(todoList, e.clientY);
const draggable = document.querySelector(".dragging");
if (afterElement == null) {
todoList.appendChild(draggable);
} else {
todoList.insertBefore(draggable, afterElement);
}
});
function positionDraggableElement(todoList, y) {
const draggableItems = [
...todoList.querySelectorAll(".todos__item:not(.dragging)"),
];
return draggableItems.reduce(
(closest, item) => {
const box = item.getBoundingClientRect();
const offset = y - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: item };
} else {
return closest;
}
},
{ offset: Number.NEGATIVE_INFINITY }
).element;
}

回购:https://github.com/DanK1368/todo__app

Live网站:https://dank1368.github.io/todo__app/

感谢的帮助

因为你做了

todoList.innerHTML += html;

当您添加todo时,那些添加/删除dragging类的事件侦听器将不再附加到-您需要重新运行

draggables.forEach((item) => {

但这不包括添加的todo

所以,我建议使用这样的功能

function initTodoDragging()
document.querySelectorAll(".todos__item").forEach((item) => {
item.addEventListener("dragstart", () => {
item.classList.add("dragging");
});
item.addEventListener("dragend", () => {
item.classList.remove("dragging");
});
});
}

在加载时调用它,以代替使用draggables的内联代码。。。也可以在之后调用

todoList.innerHTML += html;

在我看来,更好的解决方案是

// remove this as it's no longer needed
// const draggables = document.querySelectorAll(".todos__item");
// .....
// ..... SNIP .....
// .....
//template for new todo
const todoTemplate = (todo) => {
const li = document.createElement('li');
li.draggable = true;
li.classList.add("todos__item", "todo-style");
li.innerHTML = `
<button class="todos__complete btn"></button>
<p class="todos__text">${todo}</p>
<button class="todos__delete">
<img
class="todos__delete__img"
src="assets/icon-cross.svg"
alt="an icon with the symbol x that will allow you to delete the selected todo "
/>
</button>`;
initTodoDragging(li); // add the dragstart/end handlers
todoList.appendChild(li);
};
// .....
// ..... SNIP .....
// .....
//draggable todo feature
function initTodoDragging(item) {
item.addEventListener("dragstart", () => {
item.classList.add("dragging");
});
item.addEventListener("dragend", () => {
item.classList.remove("dragging");
});
}
document.querySelectorAll(".todos__item").forEach(initTodoDragging);

最新更新