在 vanilla javascript 待办事项列表中过滤待办事项
2020-09-16
2601
我正在构建一个待办事项列表,现在我被困在尝试实现 HTML 选择下拉菜单以在已完成和未完成的待办事项之间进行筛选。 我正在使用 switch 语句来选择要执行的相应块,但是我不断收到以下错误“Uncaught 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>
2个回答
我已经按照自己的理解方式完成了这项工作。希望这会对您有所帮助。
我发现您编写的代码存在一些问题
首先,应将 select 的
click
事件更改为
change
事件
其次,对于
remove
函数,您必须在将其标记为完成之前检查
e.target.id == "completeTodoButton"
,否则我们的节点选择将不起作用。
第三,对于
filterTodos
函数,您必须在切换显示之前确保节点类型为
li
。我为此使用了
todoEl.nodeName === "LI"
比较。
在 switch 案例中,您不能使用
todoEl.classList.contains("completed")
,因为完成的类未绑定到
li
,而是绑定到
li
内的
span
标记。您可以将此类移动到
li
节点并相应地设置元素,或者如果您想继续使用当前结构,则应使用
todoEl.children[0].classList.contains("completed")
,因为
li
的第一个子节点是带有
completed
类的 span。
此外,您错过了 switch 中的案例
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>
Nitheesh
2020-09-16
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>
Jaromanda X
2020-09-16