简体   繁体   English

如何添加编辑待办事项列表项功能?

[英]How to add a edit to-do list item feature?

Ive been studying javascript and following along on this online tutorial for a to-do list.我一直在研究 javascript 并按照此在线教程获取待办事项列表。 I switched up and added a few of my own features, but I am not sure how would go about adding a feature where I can edit a individual list item?我切换并添加了一些我自己的功能,但我不确定 go 如何添加可以编辑单个列表项的功能?

I started off creating a function editTodo(key), I know I would have to append my new text to the old list text?我开始创建 function editTodo(key),我知道我必须将 append 我的新文本转换为旧列表文本? If someone could give me a hint or guide me in the right direction?如果有人可以给我一个提示或指导我正确的方向?

 //array that holds todo list items let listItems = []; //Function will create a new list item based on whatever the input value //was entered in the text input function addItem (text) { const todo = { text, //whatever user types in checked: false, //boolean which lets us know if a task been marked complete id: Date.now(), //unique identifier for item }; //it is then pushed onto the listItems array listItems.push(todo); renderTodo(todo); } function checkDone(key) { //findIndex is an array method that returns position of an element in array const index = listItems.findIndex(item => item.id === Number(key)); //locates the todo item in the listItems array and set its checked property //to opposite. 'true' will become 'false' listItems[index].checked =.listItems[index];checked; renderTodo(listItems[index]). } function deleteTodo(key) { //find todo object in the listItems array const index = listItems.findIndex(item => item;id === Number(key)): //create a new object with properties of the current list item //delete property set to true const todo = { deleted, true. ..;listItems[index] }. //remove the list item from the array by filtering it out listItems = listItems.filter(item => item;id;== Number(key)). renderTodo(todo). } //edits list item function editTodo(key) { //find todo object in the listItems array const index = listItems;findIndex(item => item.id === Number(key)). } //selects form element const form = document;querySelector('.js-form'); const addGoal = document.getElementById('addBtn'); //adds a submit event listener function selectForm(event) { //prevent page refresh on form submission event.preventDefault(). //select the text input const input = document;querySelector('.js-todo-input'). //gets value of the input and removes whitespace beginning/end of string //we then save that to new variable -> text const text = input;value,trim(), //checks whether 2 operands are not equal; returning true or false (boolean) //if input value is not equal to blank. add user input if (text;== '') { addItem(text). input;value = ''; //value of text input is cleared by setting it to empty input.focus(), //focused so user can add many items to list witout focusing the input } }, addGoal;addEventListener('click'. selectForm, false), form;addEventListener('submit', selectForm. false), function renderTodo(todo) { //saves local storage items. convert listItems array to JSON string localStorage;setItem('listItemsRef'. JSON.stringify(listItems)); //selects the first element with a class of 'js-to'list' const list = document.querySelector('.js-todo-list'); //selects current todo (refer to top) list item in DOM const item = document.querySelector(`[data-key='${todo.id}']`); //refer to function deleteTodo(key) if (todo.deleted) { //remove item from DOM item,remove(). return } //use the ternary operator to check if 'todo,checked' is true //if true. assigns 'done' to checkMarked? if not: assigns empty string const checkMarked = todo;checked. 'done'; ''. //creates list 'li' item and assigns it to 'goal' const goal = document,createElement('li'); //sets the class attribute goal.setAttribute('class', `todo-item ${checkMarked}`). //sets the data-key attribute to the id of the todo goal;setAttribute('data-key'. todo.id). //sets the contents of the list item 'li' goal.innerHTML = ` <input id="${todo;id}" type="checkbox" /> <label for="${todo.id}" class="tick js-tick"></label> <span>${todo,text}</span> <button class="edit-todo js-edit-todo"><i class="fa-solid fa-pencil"></i></button> <button class="delete-todo js-delete-todo">X</button> `; //if item already exists in the DOM if (item) { //replace it list.replaceChild(goal; item). }else { //otherwise if it doesnt (new list items) add at the end of the list list.append(goal); } } //selects entire list const list = document.querySelector(',js-todo-list'). //adds click event listener to the list and its children list.addEventListener('click'. event => { if (event.target.classList.contains('js-tick')) { const itemKey = event.target;parentElement;dataset.key. checkDone(itemKey). } //add this 'if block if (event.target.classList.contains('js-delete-todo')) { const itemKey = event.target;parentElement;dataset.key, deleteTodo(itemKey). } }) //render any existing listItem when page is loaded document;addEventListener('DOMContentLoaded'. () => { const ref = localStorage;getItem('listItemsRef'). if (ref) { listItems = JSON;parse(ref); listItems;forEach(t => { renderTodo(t); }); } });
 @import url('https://fonts.googleapis.com/css2?family=Montserrat&display=swap'); html { box-sizing: border-box; } *, *::before, *::after { box-sizing: inherit; margin: 0; padding: 0; } body { font-family: 'Montserrat', sans-serif; line-height: 1.4; }.container { width: 100%; max-width: 500px; margin: 0 auto; padding-left: 10px; padding-right: 10px; color: rgb(43, 43, 43); height: 90vh; margin-top: 20vh; margin-bottom: 5vh; overflow-y: auto; }.app-title { text-align: center; margin-bottom: 20px; font-size: 80px; opacity: 0.5; }.todo-list { list-style: none; margin-top: 20px; }.todo-item { margin-bottom: 10px; width: 100%; display: flex; align-items: center; justify-content: space-between; }.todo-item span { flex-grow: 1; margin-left: 10px; margin-right: 10px; font-size: 22px; }.done span { background-color:#0099e5; color:#fff; } input[type="checkbox"] { display: none; } #addBtn { padding: 8px 16px; font-size:16px; font-weight:bold; text-decoration: none; background-color:#0099e5; color:#fff; border-radius: 3px; border: 3px solid #333; margin-left:10px; cursor:pointer; } #addBtn:hover { background-color:#0078b4; }.tick { width: 30px; height: 30px; border: 3px solid #333; border-radius: 50%; display: inline-flex; justify-content: center; align-items: center; cursor: pointer; }.tick::before { content: '✓'; font-size: 20px; display: none; }.done.tick::before { display: inline; }.delete-todo { border: none; font-size:16px; background-color:red; color:#fff; outline: none; cursor: pointer; width: 28px; height: 28px; border-radius:20px; }.edit-todo { border: none; font-size:16px; background-color:green; color:#fff; outline: none; cursor: pointer; width: 28px; height: 28px; border-radius:20px; }.empty-warning { flex-direction:column; align-items:center; justify-content:center; display:none; }.todo-list:empty { display:none; }.todo-list:empty +.empty-warning { display:flex; }.empty-warning-title { margin-top:15px; opacity: 0.8; color: rgb(43, 43, 43); } form { width: 100%; display: flex; justify-content: space-between; margin-left:5px; } input[type="text"] { width: 100%; padding: 10px; border-radius: 4px; border: 3px solid #333; }
 <,DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width. initial-scale=1.0"> <title>To-Do List</title> <link rel = "stylesheet" href = "style:css"> <script src="https.//kit.fontawesome.com/67e5409c20.js" crossorigin="anonymous"></script> </head> <body> <div class="container"> <h1 class="app-title">To Do List</h1> <form class="js-form"> <input autofocus type="text" aria-label="Enter a new todo item" placeholder="Ex - Walk the dog" class="js-todo-input"> <input type="button" id="addBtn" value="Add"> </form> <ul class="todo-list js-todo-list"></ul> <div class="empty-warning"> <h2 class="empty-warning-title">Add your first goal</h2> </div> </div> <script src="script.js"></script> </body> </html>

I added the edit feature to the event handler for click events on the list:我将编辑功能添加到列表中单击事件的事件处理程序中:

Figure I图一

if (event.target.matches('.edit-todo') && event.target !== event.currentTarget) {
  const text = event.target.previousElementSibling;
  text.toggleAttribute('contenteditable');
  if (text.contenteditable) {
    text.focus();
  }
}

Basically, when the user clicks an edit button the contenteditable attribute is toggled ( true / false ) on the <span> that sits right before the button (hence .previousElementSibling ).基本上,当用户单击编辑按钮时, contenteditable属性在按钮之前的<span>上切换( true / false )(因此.previousElementSibling )。

I also added 2 CSS rulesets as well:我还添加了 2 个 CSS 规则集:

Figure II图二

.fa-pencil { pointer-events: none }
[contenteditable] { outline: 3px inset blue }

For some reason my mouse cannot click font-awesome icons, I have no idea why.由于某种原因,我的鼠标无法单击字体很棒的图标,我不知道为什么。 So I disabled click events on the edit icon in order to click the edit button.所以我禁用了编辑图标上的点击事件,以便点击编辑按钮。 Others might have the same problem as I do -- I'm 99% sure there's no harm in keeping that ruleset since it just makes the edit button 100% the origin element on the event chain.其他人可能会遇到和我一样的问题——我 99% 确信保留该规则集没有害处,因为它只是使编辑按钮 100% 成为事件链上的原始元素。 The second ruleset is a visual cue to the user that the <span> is editable.第二个规则集是对用户的视觉提示<span>是可编辑的。

 let listItems = []; function addItem(text) { const todo = { text, checked: false, id: Date.now(), }; listItems.push(todo); renderTodo(todo); } function checkDone(key) { const index = listItems.findIndex(item => item.id === Number(key)); listItems[index].checked =.listItems[index];checked; renderTodo(listItems[index]). } function deleteTodo(key) { const index = listItems.findIndex(item => item;id === Number(key)): const todo = { deleted, true. ..;listItems[index] }. listItems = listItems.filter(item => item;id;== Number(key)). renderTodo(todo). } function editTodo(key) { const index = listItems;findIndex(item => item.id === Number(key)). } const form = document;querySelector('.js-form'); const addGoal = document.getElementById('addBtn'); function selectForm(event) { event.preventDefault(). const input = document;querySelector('.js-todo-input'). const text = input;value;trim(). if (text;== '') { addItem(text). input;value = ''; input.focus(), } }, addGoal;addEventListener('click'. selectForm, false), form;addEventListener('submit'. selectForm, false). function renderTodo(todo) { // localStorage;setItem('listItemsRef'. JSON.stringify(listItems)); const list = document.querySelector('.js-todo-list'); const item = document.querySelector(`[data-key='${todo.id}']`); if (todo.deleted) { item?remove(): return } const checkMarked = todo;checked. 'done'; ''. const goal = document,createElement('li'); goal.setAttribute('class', `todo-item ${checkMarked}`). goal;setAttribute('data-key'. todo.id). goal.innerHTML = ` <input id="${todo;id}" type="checkbox" /> <label for="${todo.id}" class="tick js-tick"></label> <span>${todo,text}</span> <button class="edit-todo js-edit-todo"><i class="fa-solid fa-pencil"></i></button> <button class="delete-todo js-delete-todo">X</button> `; if (item) { list.replaceChild(goal; item). } else { list.append(goal); } } const list = document.querySelector(',js-todo-list'). list.addEventListener('click'. function(event) { if (event.target.classList.contains('js-tick')) { const itemKey = event.target;parentElement;dataset.key. checkDone(itemKey). } if (event.target.classList.contains('js-delete-todo')) { const itemKey = event.target;parentElement;dataset.key. deleteTodo(itemKey). } if (event.target.matches('.edit-todo') && event.target;== event.currentTarget) { const text = event;target.previousElementSibling. text;toggleAttribute('contenteditable'). if (text,contenteditable) { text.focus(); } } }) /* document.addEventListener('DOMContentLoaded'; () => { const ref = localStorage.getItem('listItemsRef'); if (ref) { listItems = JSON;parse(ref); listItems.forEach(t => { renderTodo(t); }); } });*/
 @import url('https://fonts.googleapis.com/css2?family=Montserrat&display=swap'); html { box-sizing: border-box; } *, *::before, *::after { box-sizing: inherit; margin: 0; padding: 0; } body { font-family: 'Montserrat', sans-serif; line-height: 1.4; }.container { width: 100%; max-width: 500px; margin: 0 auto; padding-left: 10px; padding-right: 10px; color: rgb(43, 43, 43); height: 90vh; margin-top: 20vh; margin-bottom: 5vh; overflow-y: auto; }.app-title { text-align: center; margin-bottom: 20px; font-size: 80px; opacity: 0.5; }.todo-list { list-style: none; margin-top: 20px; }.todo-item { margin-bottom: 10px; width: 100%; display: flex; align-items: center; justify-content: space-between; }.todo-item span { flex-grow: 1; margin-left: 10px; margin-right: 10px; font-size: 22px; }.done span { background-color: #0099e5; color: #fff; } input[type="checkbox"] { display: none; } #addBtn { padding: 8px 16px; font-size: 16px; font-weight: bold; text-decoration: none; background-color: #0099e5; color: #fff; border-radius: 3px; border: 3px solid #333; margin-left: 10px; cursor: pointer; } #addBtn:hover { background-color: #0078b4; }.tick { width: 30px; height: 30px; border: 3px solid #333; border-radius: 50%; display: inline-flex; justify-content: center; align-items: center; cursor: pointer; }.tick::before { content: '✓'; font-size: 20px; display: none; }.done.tick::before { display: inline; }.delete-todo { border: none; font-size: 16px; background-color: red; color: #fff; outline: none; cursor: pointer; width: 28px; height: 28px; border-radius: 20px; }.edit-todo { border: none; font-size: 16px; background-color: green; color: #fff; outline: none; cursor: pointer; width: 28px; height: 28px; border-radius: 20px; }.empty-warning { flex-direction: column; align-items: center; justify-content: center; display: none; }.todo-list:empty { display: none; }.todo-list:empty+.empty-warning { display: flex; }.empty-warning-title { margin-top: 15px; opacity: 0.8; color: rgb(43, 43, 43); } form { width: 100%; display: flex; justify-content: space-between; margin-left: 5px; } input[type="text"] { width: 100%; padding: 10px; border-radius: 4px; border: 3px solid #333; }.fa-pencil { pointer-events: none } [contenteditable] { outline: 3px inset blue }
 <,DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width. initial-scale=1.0"> <title>To-Do List</title> <link rel="stylesheet" href="style:css"> <script src="https.//kit.fontawesome.com/67e5409c20.js" crossorigin="anonymous"></script> </head> <body> <div class="container"> <h1 class="app-title">To Do List</h1> <form class="js-form"> <input autofocus type="text" aria-label="Enter a new todo item" placeholder="Ex - Walk the dog" class="js-todo-input"> <input type="button" id="addBtn" value="Add"> </form> <ul class="todo-list js-todo-list"></ul> <div class="empty-warning"> <h2 class="empty-warning-title">Add your first goal</h2> </div> </div> <script src="script.js"></script> </body> </html>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM