我一直在努力摆脱我做的待办事项清单。
所以我的问题是排序。当有人添加要执行的操作时,我将对象推送到数组。
问题是,当你勾选完成后,它会转到已完成的部分,但如果你决定再次使其不完整,那么它会回到列表的顶部(我认为这是最好的方式,而不是深入到底部列表)。如果您不这么认真,请告诉我。
所以它回到列表的顶部,但它的数组位置从未改变,所以在刷新时它只是回到正常的数组位置。我真的不希望列表重新进行刷新。
我问了一个类似的问题并得到了回复说要使用'sort'方法,所以我在对象上添加了'iscomplete'属性,所以当你完成然后未完成时,它会将这些排序到顶部。
但如果您有多个项目完成,那么未完成您只会遇到同样的问题。
不确定如何解决此问题。
HTML
<div class="to-do">
<div class="container">
<div class="to-do-entry">
<div class="to-do-task-holder">
<input id="task-holder" type="text" placeholder="Enter a to do!">
<svg id="add-to-do" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="5" x2="12" y2="19"/>
<line x1="5" y1="12" x2="19" y2="12"/>
</svg>
</div>
</div>
</div>
<!-- Task -->
<!-- Uncompleted -->
<div class="container">
<h3 class="to-do-title to-do-title-uncompleted">Uncompleted Tasks</h3>
</div>
<ul id="uncompleted-tasks"></ul>
<!-- Completed -->
<div class="container">
<h3 class="to-do-title to-do-title-completed">Completed Tasks</h3>
</div>
<ul id="completed-tasks"></ul>
</div>
JS
// To do list
var storeToDos = [];
// Cache DOM
var addToDo = document.getElementById('add-to-do');
var taskHolder = document.getElementById('task-holder');
var uncompleteTasks = document.getElementById('uncompleted-tasks');
var completedTasks = document.getElementById('completed-tasks');
// Bind events
var bindEvents = function(listItem, checkboxEventHandler) {
// Delete
var deleteToDo = listItem.querySelector('.delete-to-do');
deleteToDo.addEventListener('click', deleteTask);
// Edit
listItem.querySelector('.edit-to-do').addEventListener('click', editTask);
listItem.querySelector('.edit-holder').addEventListener('keyup', editTaskEnter);
// Checkbox
var checkbox = listItem.querySelector('input.edit-to-do');
checkbox.onchange = checkboxEventHandler;
}
// Create list item
var createListItem = function() {
var listItem = document.createElement('li');
var deleteToDo = document.createElement('div');
deleteToDo.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="#FFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M7.1 7.1l9.8 9.8M7.1 16.9l9.8-9.8"/></svg>';
deleteToDo.classList.add('delete-to-do');
var editToDo = document.createElement('div');
editToDo.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" stroke="#FFF" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" d="M16 3l5 5L8 21H3v-5z"/></svg>';
editToDo.classList.add('edit-to-do');
var toDoStatus = document.createElement('input');
toDoStatus.type = 'checkbox';
toDoStatus.classList.add('edit-to-do');
var editHolder = document.createElement('input');
editHolder.type = 'text';
editHolder.classList.add('edit-holder');
listItem.appendChild(deleteToDo);
listItem.appendChild(editToDo);
listItem.appendChild(toDoStatus);
listItem.appendChild(editHolder);
return listItem;
}
// Add task
var addTask = function(e) {
var listItem = createListItem();
var taskHolderValue = taskHolder.value;
if(taskHolderValue) {
document.querySelector('body').classList.add('to-do-activated');
var taskHolderElement = document.createElement('label');
taskHolderElement.classList.add('to-do-item');
listItem.insertBefore(taskHolderElement, listItem.childNodes[0]);
var storeToDosObj = {
value: '',
id: null,
completed: false,
didComplete: false
}
storeToDosObj.value = taskHolderValue;
var listId = storeToDosObj.id = Date.now();
listItem.id = listId;
uncompleteTasks.insertBefore(listItem, uncompleteTasks.childNodes[0]);
var storedToDos = localStorage.getItem('todos');
if(storedToDos) {
var storedToDosArr = JSON.parse(localStorage.todos);
storedToDosArr.push(storeToDosObj);
localStorage.setItem('todos', JSON.stringify(storedToDosArr));
} else {
console.log(storeToDos);
storeToDos.push(storeToDosObj);
localStorage.setItem('todos', JSON.stringify(storeToDos));
}
taskHolderElement.innerHTML = taskHolderValue;
bindEvents(listItem, taskCompleted);
taskHolder.value = '';
} else {
alert("You didn't add a to a to do!");
}
}
var addTaskEnter = function(e) {
var key = 'which' in e ? e.which : e.keyCode;
if(key === 13) {
addTask();
}
}
// Delete task
var deleteTask = function() {
var listItem = this.parentNode;
var parentItem = listItem.parentNode;
var getToDos = JSON.parse(localStorage.getItem('todos'));
for(var b=0; b<getToDos.length; b++) {
if(getToDos[b].id == listItem.id) {
getToDos.splice(b, 1);
localStorage.setItem('todos', JSON.stringify(getToDos));
}
}
parentItem.removeChild(listItem);
}
// Edit task
var editTask = function() {
var defaultValue = this.parentNode.querySelector('label').innerHTML;
var listItem = this.parentNode;
var listParent = this.parentNode;
var editedValue = listParent.querySelector('input.edit-holder').value;
if(listItem.classList.contains('editing') && editedValue) {
listParent.querySelector('label').innerHTML = editedValue;
var storedLocalStorage = JSON.parse(localStorage.todos);
for(var d=0; d<storedLocalStorage.length; d++) {
if(storedLocalStorage[d].id == listItem.id) {
storedLocalStorage[d].value = editedValue;
storedLocalStorage[d].completed = false;
localStorage.setItem('todos', JSON.stringify(storedLocalStorage));
}
}
}
listItem.classList.toggle('editing');
listParent.querySelector('input.edit-holder').value = '';
}
// Edit task enter
var editTaskEnter = function(e) {
var key = 'which' in e ? e.which : e.keyCode;
if(key === 13) {
editTask.call(this);
}
}
// Task completed
var taskCompleted = function() {
var listItem = this.parentNode;
var storedCompletion = JSON.parse(localStorage.getItem('todos'));
if(storedCompletion) {
if(listItem.classList.contains('editing')) {
}
for(var e=0; e<storedCompletion.length; e++) {
if(storedCompletion[e].id == listItem.id) {
if(storedCompletion[e].completed === true) {
this.parentNode.classList.add('completed');
uncompleteTasks.insertBefore(listItem, uncompleteTasks.childNodes[0]);
this.parentNode.classList.remove('completed');
bindEvents(listItem, taskCompleted);
storedCompletion[e].completed = false;
storedCompletion[e].didComplete = false;
} else {
completedTasks.insertBefore(listItem, completedTasks.childNodes[0]);
this.parentNode.classList.add('completed');
bindEvents(listItem, taskUncompleted);
storedCompletion[e].completed = true;
storedCompletion[e].didComplete = true;
}
localStorage.setItem('todos', JSON.stringify(storedCompletion));
}
}
}
}
// Task uncompleted
var taskUncompleted = function() {
var listItem = this.parentNode;
uncompleteTasks.insertBefore(listItem, uncompleteTasks.childNodes[0]);
this.parentNode.classList.remove('completed');
bindEvents(listItem, taskCompleted);
if(localStorage) {
var storedCompletion = JSON.parse(localStorage.getItem('todos'));
}
for(var f=0; f<storedCompletion.length; f++) {
if(storedCompletion[f].id == listItem.id) {
storedCompletion[f].completed = false;
localStorage.setItem('todos', JSON.stringify(storedCompletion));
}
}
}
// Add task
addToDo.addEventListener("click", addTask);
taskHolder.addEventListener("keyup", addTaskEnter);
// Loop over complete tasks
for(i=0; i<completedTasks.length; i++) {
var listItem = completedTasks[i];
uncompleteTasks.appendChild(listItem);
bindEvents(listItem, completedTasks);
}
// Render local storage
var getToDos = JSON.parse(localStorage.getItem('todos'));
getToDos.reverse();
getToDos.sort(function(a, b){
return b.didComplete > a.didComplete;
});
if(getToDos) {
for(i=0; i<getToDos.length; i++) {
var listItem = createListItem();
listItem.id = getToDos[i].id;
var storedListItem = document.createElement('label');
storedListItem.innerHTML = getToDos[i].value;
listItem.insertBefore(storedListItem, listItem.childNodes[0]);
if(getToDos[i].completed === true) {
listItem.querySelector('input').checked = true;
completedTasks.appendChild(listItem);
listItem.classList.add('completed');
} else {
uncompleteTasks.appendChild(listItem);
}
bindEvents(listItem, taskCompleted)
}
}
if(JSON.parse(localStorage.getItem('todos')).length > 0) {
document.querySelector('body').classList.add('to-do-activated');
}
答案 0 :(得分:2)
需要排序的代码很多。
简而言之,您想要的是当您移动项目时,在底层数组中移动它,而不仅仅是在渲染的HTML中。
它之所以离开是因为你只是将它放在HTML元素的顶部,但基础数据没有重新排列。
当你去完成/取消完成一个项目时,除了在DOM中渲染它之外,你还应该移动你存储的项目中的项目。
这样的事情会将项目从当前位置移到列表顶部:
const storedItems = []; // get from somewhere
let indexOfItem = 5; // the item you're going to move
storedItems.shift(storedItems.splice(indexOfItem, 1)[0]);
该做的是将项目从其当前位置(使用splice()
)移除,然后将shift()
(将其置于前面)阵列。
这样可以让你的DOM保持顺序。当你去完成它时,你可以做类似的事情,只需将索引更改为与DOM相同的位置。
更好的解决方案可能是让一个函数根据您存储的数据重新呈现整个DOM,然后所有函数只更改它们的数组并告诉它重绘。像React和AngularJS那样的框架(虽然它们确实有一些奇特的优化)。
答案 1 :(得分:0)
您发布了大量代码,包括许多与问题无关的功能,因此提供建议更加困难。
也许当用户取消选中某个项目时,您可以从阵列中删除该任务并将其重新添加到阵列的前面?您可以使用unshift方法将某些内容添加到数组的前面。