我正在构建一个待办事项列表,而现在我一直在尝试实现一个HTML-select下拉列表来过滤已完成和未完成的待办事项。我使用Switch语句来选择要执行的各个块,但是我一直收到以下错误“未捕获TypeError:无法设置未定义的属性'display‘”,但我不知道哪些元素是未定义的。
const input = document.getElementById('input')
const addTodoButton = document.getElementById('addTodoButton')
const todoUL = document.getElementById('todoUL')
const filterOptions = document.querySelector('.filter-todos')
addTodoButton.addEventListener('click', addTodo)
todoUL.addEventListener('click', remove);
filterOptions.addEventListener('click', filterTodos);
// Add todo
function addTodo(e) {
e.preventDefault()
const todoText = input.value
const todoEl = `<li><span>${todoText}</span> <button class="delete" id="deleteTodoButton"><i class="far fa-trash-alt"></i>Delete</button> <button class="complete" id="completeTodoButton"><i class="fas fa-check"></i>Completed</button></li>`
input.value = ""
input.focus()
if (!todoText) {
alert('You must type a todo')
} else {
todoUL.insertAdjacentHTML("beforeend", todoEl)
}
}
// Remove/Complete todo
function remove(e) {
if (e.target.id == 'deleteTodoButton') {
e.target.parentElement.remove()
input.focus()
} else {
e.target.previousElementSibling.previousElementSibling.classList.toggle('completed')
input.focus()
}
}
function filterTodos(e) {
const todos = todoUL.childNodes
todos.forEach(function (todoEl) {
switch (e.target.value) {
case "all":
todoEl.style.display = "flex"
break;
case "completed":
if (todoEl.classList.contains("completed")) {
todoEl.style.display = "flex"
} else {
todoEl.style.display = "none"
}
break;
}
})
}ul {
list-style: none
}
.completed {
text-decoration: line-through
}<div class="form-container">
<h1>Todo List App</h1>
<form id="form">
<input type="text" id="input" autocomplete="off" placeholder="Enter your todo">
<button type="submit" class="add-todo" id="addTodoButton">Add</button>
<select name="todos" class="filter-todos">
<option value="all">All</option>
<option value="completed">Completed</option>
<option value="uncompleted">Uncompleted</option>
</select>
</form>
<ul id="todoUL">
</ul>
</div>
发布于 2020-09-16 21:56:28
我已经在我的解释方式中做到了这一点。希望这能在某些方面对你有所帮助。
我已经发现您编写的代码中存在一些问题
首先应该将select的click事件更改为change事件
第二,在使用remove函数的情况下,您必须在将e.target.id == "completeTodoButton"标记为完成之前检查它,否则我们的节点选择将不起作用。
第三,在使用filterTodos函数的情况下,在切换显示之前必须确保节点类型为li。为此,我使用了todoEl.nodeName === "LI"比较。
在切换用例中,您不能使用todoEl.classList.contains("completed"),因为完成的类并不绑定到li,而是绑定到li中的span标记。您可以将这个类移动到li节点并相应地存储元素,或者如果您想继续使用当前结构,则应该使用todoEl.children[0].classList.contains("completed"),因为li的第一个子节点是具有completed类的跨度。
此外,您还遗漏了交换机中的case uncompleted。
ul {
list-style: none;
}
.completed {
text-decoration: line-through;
}<div class="form-container">
<h1>Todo List App</h1>
<form id="form">
<input
type="text"
id="input"
autocomplete="off"
placeholder="Enter your todo"
/>
<button type="submit" class="add-todo" id="addTodoButton">Add</button>
<select name="todos" class="filter-todos">
<option value="all">All</option>
<option value="completed">Completed</option>
<option value="uncompleted">Uncompleted</option>
</select>
</form>
<ul id="todoUL"></ul>
</div>
<script>
const input = document.getElementById("input");
const addTodoButton = document.getElementById("addTodoButton");
const todoUL = document.getElementById("todoUL");
const filterOptions = document.querySelector(".filter-todos");
addTodoButton.addEventListener("click", addTodo);
todoUL.addEventListener("click", remove);
filterOptions.addEventListener("change", filterTodos);
// Add todo
function addTodo(e) {
e.preventDefault();
const todoText = input.value;
const todoEl = `<li><span>${todoText}</span>
<button class="delete" id="deleteTodoButton"><i class="far fa-trash-alt"></i>Delete</button>
<button class="complete" id="completeTodoButton"><i class="fas fa-check"></i>Completed</button></li>`;
input.value = "";
input.focus();
if (!todoText) {
alert("You must type a todo");
} else {
todoUL.insertAdjacentHTML("beforeend", todoEl);
}
}
// Remove/Complete todo
function remove(e) {
if (e.target.id == "deleteTodoButton") {
e.target.parentElement.remove();
input.focus();
} else if (e.target.id == "completeTodoButton") {
e.target.previousElementSibling.previousElementSibling.classList.toggle(
"completed"
);
input.focus();
}
}
function filterTodos(e) {
const todos = todoUL.childNodes;
todos.forEach(function(todoEl) {
if (todoEl.nodeName === "LI") {
switch (e.target.value) {
case "all":
todoEl.style.display = "flex";
break;
case "completed":
if (todoEl.children[0].classList.contains("completed")) {
todoEl.style.display = "flex";
} else {
todoEl.style.display = "none";
}
break;
case "uncompleted":
if (todoEl.children[0].classList.contains("completed")) {
todoEl.style.display = "none";
} else {
todoEl.style.display = "flex";
}
break;
}
}
});
}
</script>
发布于 2020-09-16 21:38:52
const input = document.getElementById('input')
const addTodoButton = document.getElementById('addTodoButton')
const todoUL = document.getElementById('todoUL')
const filterOptions = document.querySelector('.filter-todos')
addTodoButton.addEventListener('click', addTodo)
todoUL.addEventListener('click', remove);
filterOptions.addEventListener('click', filterTodos);
// Add todo
function addTodo(e) {
e.preventDefault()
const todoText = input.value
const todoEl = `<li><span>${todoText}</span> <button class="delete" id="deleteTodoButton"><i class="far fa-trash-alt"></i>Delete</button> <button class="complete" id="completeTodoButton"><i class="fas fa-check"></i>Completed</button></li>`
input.value = ""
input.focus()
if (!todoText) {
alert('You must type a todo')
} else {
todoUL.insertAdjacentHTML("beforeend", todoEl)
}
}
// Remove/Complete todo
function remove(e) {
if (e.target.id == 'deleteTodoButton') {
e.target.parentElement.remove()
input.focus()
} else {
e.target.previousElementSibling.previousElementSibling.classList.toggle('completed')
input.focus()
}
}
function filterTodos(e) {
const todos = todoUL.querySelectorAll('li > span');
todos.forEach(function (todoEl) {
const tgt = todoEl.parentElement;
switch (e.target.value) {
case "all":
tgt.style.display = "flex"
break;
case "completed":
if (todoEl.classList.contains("completed")) {
tgt.style.display = "flex"
} else {
tgt.style.display = "none"
}
break;
case "uncompleted":
if (todoEl.classList.contains("completed")) {
tgt.style.display = "none"
} else {
tgt.style.display = "flex"
}
break;
}
})
}ul {
list-style: none
}
.completed {
text-decoration: line-through
}<div class="form-container">
<h1>Todo List App</h1>
<form id="form">
<input type="text" id="input" autocomplete="off" placeholder="Enter your todo">
<button type="submit" class="add-todo" id="addTodoButton">Add</button>
<select name="todos" class="filter-todos">
<option value="all">All</option>
<option value="completed">Completed</option>
<option value="uncompleted">Uncompleted</option>
</select>
</form>
<ul id="todoUL">
</ul>
</div>
https://stackoverflow.com/questions/63921107
复制相似问题