尝试为 Javascript 中的待办事项列表应用程序做一个过滤器,但苦苦挣扎
Trying to do a filter for a to-do list app in Javascript but struggling
我有一个待办事项列表,它工作得很好,但我正在尝试过滤它,但我有点吃力。
基本上,每个任务都是一个对象,每个对象都有 text、id 和 checked 属性。
例如,我想只显示在我按“激活”时未选中的任务。
希望对你有所帮助。
这是一张图片以供更多说明:
/* Selectors */
const switcher = document.querySelector(' input[Type="checkbox"]');
const body = document.body;
const formT = document.querySelector(`[data-new-todo-form]`)
const inputT = document.querySelector(`[data-new-todo-input]`)
const todoList = document.getElementById('todo-list');
const filterList = document.querySelector('.controls-list')
/* array that holds tasks */
let tasks = [];
/* EVENT LISTENERS */
switcher.addEventListener('change', (e) => {
if(e.target.checked) {
body.classList.replace('light', 'dark')
} else {
body.classList.replace('dark', 'light')
}
})
formT.addEventListener('submit', e => {
e.preventDefault()
let text = inputT.value.trim();
if(text !== '') {
addTask(text);
inputT.value = '';
inputT.focus();
}
})
todoList.addEventListener('click', e => {
if (e.target.classList.contains('js-tick')) {
const itemKey = e.target.parentElement.dataset.key;
toggleDone(itemKey);
}
if (e.target.classList.contains('delete')) {
const itemKey = e.target.parentElement.dataset.key;
deleteTodo(itemKey);
counter();
}
});
document.addEventListener('DOMContentLoaded', () => {
const ref = localStorage.getItem('tasksRef');
if (ref) {
tasks = JSON.parse(ref);
tasks.forEach(task => {
renderTodo(task);
counter();
});
}
});
/* FUNCTIONS */
/* create a todo object */
const addTask = (text) => {
const todoTask = {
text,
checked: false,
id: Date.now(),
}
tasks.push(todoTask);
renderTodo(todoTask);
};
const renderTodo = (todoTask)=> {
localStorage.setItem('tasksRef', JSON.stringify(tasks));
const item = document.querySelector(`[data-key='${todoTask.id}']`);
if (todoTask.deleted) {
// remove the item from the DOM
item.remove();
return
}
const isChecked = todoTask.checked ? 'done': '';
const node = document.createElement('li')
node.setAttribute('class', `todo-item ${isChecked}`);
node.setAttribute('data-key', todoTask.id);
node.innerHTML = `
<input class="js-tick" id="${todoTask.id}" type="checkbox" ${isChecked ? "checked" : ""}/>
<span>${todoTask.text}</span>
<img class="delete" width="15px" height='15px' src="/images/icon-cross.svg" alt="cross">`
;
todoList.append(node);
if (item) {
node.replaceWith(item)
} else {
todoList.append(node)
}
counter();
}
const toggleDone = (key) => {
const index = tasks.findIndex(task=> task.id === Number(key));
tasks[index].checked = !tasks[index].checked;
renderTodo(tasks[index]);
}
const deleteTodo = (key) => {
const index = tasks.findIndex(item => item.id === Number(key));
const todoTask = {
deleted: true,
...tasks[index]
};
tasks = tasks.filter(item => item.id !== Number(key));
renderTodo(todoTask);
}
const counter = () => {
const itemsCounter = tasks.filter(task=> !task.checked)
const count = document.getElementById('todosLeft');
const counterString = itemsCounter.length === 1 ? 'item' : 'items'
count.innerText = `${itemsCounter.length} ${counterString} left`
}
这里是 HTML:
<body class="light">
<section class="header">
</section>
<div class="container">
<div class="title-theme">
<h1>Todo</h1>
<input type="checkbox" id="switch-l" class="themeSwitch">
<label for="switch-l" id="switch" class="themeSwitch-label"></label>
</div>
<div class="todosInput">
<div id="mark"></div>
<form class="form" action="" data-new-todo-form>
<input id="todos" data-new-todo-input type="text" placeholder="Create a new todo..." >
</form>
</div>
<div class="myTodos">
<ul id="todo-list">
<--! THE TASKS GOES HERE !-->
</ul>
</div>
<div class="controls">
<p id="todosLeft">items left</p><!-- Add dynamic number -->
<div class="controls-list-div">
<ul class="controls-list" data-lists>
<li>All</li>
<li>Active</li>
<li>Completed</li>
</ul>
</div>
Clear Completed
</div>
</div>
<div class="instruc">
<p>Drag and drop to reorder list</p>
</div>
首先你的 TodoList 需要是不可变的,因为在你点击所有 TodoList 后应该显示所有 Todos。
const renderActiveTodos = () => {
const ref = localStorage.getItem('tasksRef');
if (ref) {
tasks = JSON.parse(ref);
tasks.filter(item => !item.check).forEach(task => {
renderTodo(task, true);
counter();
});
}
}
const renderAllTodos = () => {
const ref = localStorage.getItem('tasksRef');
if (ref) {
tasks = JSON.parse(ref);
tasks.forEach(task => {
renderTodo(task, true);
counter();
});
}
}
const renderCompletedTodos = () => {
const ref = localStorage.getItem('tasksRef');
if (ref) {
tasks = JSON.parse(ref);
tasks.filter(item => item.check).forEach(task => {
renderTodo(task, true);
counter();
});
}
}
但是你应该在你的 renderTodo 函数中添加 preventMutableStorage 来防止本地存储中的数据。然后你可以return返回完整的待办事项列表如果你点击全部
const renderTodo = (todoTask, preventMutableStorage)=> {
if(!preventMutableStorage){
localStorage.setItem('tasksRef', JSON.stringify(tasks));
}
.....
}
为什么我要更改 renderTodo:
首先假设我们有 todoList = [{id:1, check:false}, {id:2, check:true}, {id:3, check:true}]
当我单击活动时,将调用 renderActiveTodos:
It get data from localstorage
Filter data with check=false => [{id:1, check:false}]
Then we loop through it then call renderTodo
In renderTodo it first set the localstorage again then now the Todo in Localstorage is [{id:1, check:false}]
那么下次我们点击全部:
It can't show [{id:2, check:true}, {id:3, check:true}] cause we already update the todoList in localstorage
这就是我添加 preventMutableStorage 参数以防止本地存储 TodoList 更新的原因
我刚刚在您的代码中发现了一些东西。但所有人都会修复这是工作代码。
我有一个待办事项列表,它工作得很好,但我正在尝试过滤它,但我有点吃力。 基本上,每个任务都是一个对象,每个对象都有 text、id 和 checked 属性。 例如,我想只显示在我按“激活”时未选中的任务。
希望对你有所帮助。 这是一张图片以供更多说明:
/* Selectors */
const switcher = document.querySelector(' input[Type="checkbox"]');
const body = document.body;
const formT = document.querySelector(`[data-new-todo-form]`)
const inputT = document.querySelector(`[data-new-todo-input]`)
const todoList = document.getElementById('todo-list');
const filterList = document.querySelector('.controls-list')
/* array that holds tasks */
let tasks = [];
/* EVENT LISTENERS */
switcher.addEventListener('change', (e) => {
if(e.target.checked) {
body.classList.replace('light', 'dark')
} else {
body.classList.replace('dark', 'light')
}
})
formT.addEventListener('submit', e => {
e.preventDefault()
let text = inputT.value.trim();
if(text !== '') {
addTask(text);
inputT.value = '';
inputT.focus();
}
})
todoList.addEventListener('click', e => {
if (e.target.classList.contains('js-tick')) {
const itemKey = e.target.parentElement.dataset.key;
toggleDone(itemKey);
}
if (e.target.classList.contains('delete')) {
const itemKey = e.target.parentElement.dataset.key;
deleteTodo(itemKey);
counter();
}
});
document.addEventListener('DOMContentLoaded', () => {
const ref = localStorage.getItem('tasksRef');
if (ref) {
tasks = JSON.parse(ref);
tasks.forEach(task => {
renderTodo(task);
counter();
});
}
});
/* FUNCTIONS */
/* create a todo object */
const addTask = (text) => {
const todoTask = {
text,
checked: false,
id: Date.now(),
}
tasks.push(todoTask);
renderTodo(todoTask);
};
const renderTodo = (todoTask)=> {
localStorage.setItem('tasksRef', JSON.stringify(tasks));
const item = document.querySelector(`[data-key='${todoTask.id}']`);
if (todoTask.deleted) {
// remove the item from the DOM
item.remove();
return
}
const isChecked = todoTask.checked ? 'done': '';
const node = document.createElement('li')
node.setAttribute('class', `todo-item ${isChecked}`);
node.setAttribute('data-key', todoTask.id);
node.innerHTML = `
<input class="js-tick" id="${todoTask.id}" type="checkbox" ${isChecked ? "checked" : ""}/>
<span>${todoTask.text}</span>
<img class="delete" width="15px" height='15px' src="/images/icon-cross.svg" alt="cross">`
;
todoList.append(node);
if (item) {
node.replaceWith(item)
} else {
todoList.append(node)
}
counter();
}
const toggleDone = (key) => {
const index = tasks.findIndex(task=> task.id === Number(key));
tasks[index].checked = !tasks[index].checked;
renderTodo(tasks[index]);
}
const deleteTodo = (key) => {
const index = tasks.findIndex(item => item.id === Number(key));
const todoTask = {
deleted: true,
...tasks[index]
};
tasks = tasks.filter(item => item.id !== Number(key));
renderTodo(todoTask);
}
const counter = () => {
const itemsCounter = tasks.filter(task=> !task.checked)
const count = document.getElementById('todosLeft');
const counterString = itemsCounter.length === 1 ? 'item' : 'items'
count.innerText = `${itemsCounter.length} ${counterString} left`
}
这里是 HTML:
<body class="light">
<section class="header">
</section>
<div class="container">
<div class="title-theme">
<h1>Todo</h1>
<input type="checkbox" id="switch-l" class="themeSwitch">
<label for="switch-l" id="switch" class="themeSwitch-label"></label>
</div>
<div class="todosInput">
<div id="mark"></div>
<form class="form" action="" data-new-todo-form>
<input id="todos" data-new-todo-input type="text" placeholder="Create a new todo..." >
</form>
</div>
<div class="myTodos">
<ul id="todo-list">
<--! THE TASKS GOES HERE !-->
</ul>
</div>
<div class="controls">
<p id="todosLeft">items left</p><!-- Add dynamic number -->
<div class="controls-list-div">
<ul class="controls-list" data-lists>
<li>All</li>
<li>Active</li>
<li>Completed</li>
</ul>
</div>
Clear Completed
</div>
</div>
<div class="instruc">
<p>Drag and drop to reorder list</p>
</div>
首先你的 TodoList 需要是不可变的,因为在你点击所有 TodoList 后应该显示所有 Todos。
const renderActiveTodos = () => {
const ref = localStorage.getItem('tasksRef');
if (ref) {
tasks = JSON.parse(ref);
tasks.filter(item => !item.check).forEach(task => {
renderTodo(task, true);
counter();
});
}
}
const renderAllTodos = () => {
const ref = localStorage.getItem('tasksRef');
if (ref) {
tasks = JSON.parse(ref);
tasks.forEach(task => {
renderTodo(task, true);
counter();
});
}
}
const renderCompletedTodos = () => {
const ref = localStorage.getItem('tasksRef');
if (ref) {
tasks = JSON.parse(ref);
tasks.filter(item => item.check).forEach(task => {
renderTodo(task, true);
counter();
});
}
}
但是你应该在你的 renderTodo 函数中添加 preventMutableStorage 来防止本地存储中的数据。然后你可以return返回完整的待办事项列表如果你点击全部
const renderTodo = (todoTask, preventMutableStorage)=> {
if(!preventMutableStorage){
localStorage.setItem('tasksRef', JSON.stringify(tasks));
}
.....
}
为什么我要更改 renderTodo:
首先假设我们有 todoList = [{id:1, check:false}, {id:2, check:true}, {id:3, check:true}]
当我单击活动时,将调用 renderActiveTodos:
It get data from localstorage
Filter data with check=false => [{id:1, check:false}]
Then we loop through it then call renderTodo
In renderTodo it first set the localstorage again then now the Todo in Localstorage is [{id:1, check:false}]
那么下次我们点击全部:
It can't show [{id:2, check:true}, {id:3, check:true}] cause we already update the todoList in localstorage
这就是我添加 preventMutableStorage 参数以防止本地存储 TodoList 更新的原因
我刚刚在您的代码中发现了一些东西。但所有人都会修复这是工作代码。