每次提交时发生类似事件时都会附加旧事件
Old events getting appended every time similar event occurs on submit
我试图在原版 JS 中制作待办事项列表。有一个添加按钮可以在列表中添加项目。当为特定项目选择编辑选项时,添加按钮变为编辑并且输入框接受编辑的值。
当我编辑第一个项目时,它工作正常。但是当我编辑第二个项目时,第一个和第二个项目的值都会发生变化。编辑第三项时也是如此,第二项和第一项的值也会发生变化。我不确定为什么会这样。
const todoForm = document.querySelector('.todo-form');
// select the input box
const todoInput = document.querySelector('.todo-input');
// select the <ul> with class="todo-items"
const todoItemsList = document.querySelector('.todo-items');
const butt = document.querySelector('.add-button');
let todos = [];
todoForm.addEventListener('submit', (e) => {
if(butt.innerHTML === "Add"){
console.log("Add");
e.preventDefault();
AddTo(todoInput.value);
console.log(todoInput.value);}
});
function AddTo(item){
console.log(item);
if(item!= ''){
const todo = {
id : Date.now(),
name : item,
completed : false
}
todos.push(todo);
addToLocal();
todoInput.value = '';
}
}
function renderTo(){
todoItemsList.innerHTML = '';
todos.forEach((item) => {
const checked = item.completed ? 'checked' : null;
const li = document.createElement('li');
li.setAttribute('class','item');
li.setAttribute('data-key', item.id);
if(item.completed == true){
li.classList.add('checked');
}
li.innerHTML = `<input type = "checkbox" class = "checkbox" ${checked}> ${item.name} <button class = "delete-button">X</button> <button class = "edit-button">E</button>`;
todoItemsList.append(li);
})
}
function addToLocal(){
localStorage.setItem('todos', JSON.stringify(todos));
renderTo();
}
function getFromLocal(){
const reference = localStorage.getItem('todos');
if(reference){
todos = JSON.parse(reference);
renderTo()
}
}
getFromLocal();
todoItemsList.addEventListener('click', (e) => {
if(e.target.type === 'checkbox'){
toggle(e.target.parentElement.getAttribute('data-key'));
}
if(e.target.classList.contains('delete-button')){
del(e.target.parentElement.getAttribute('data-key'));
}
if(e.target.classList.contains('edit-button')){
edit(e.target.parentElement.getAttribute('data-key'));
}
})
function toggle(id){
todos.forEach((item) => {
if(item.id == id){
item.completed = !item.completed;
}
});
addToLocal();
}
function del(id){
todos = todos.filter((item) => {
return item.id != id;
});
addToLocal();
}
function edit(id){
butt.innerHTML = "Edit";
todos.forEach((item) => {
if(item.id == id){
todoInput.value = item.name;
console.log(item);
todoForm.addEventListener('submit', (e) => {
e.preventDefault();
console.log(item);
item.name = todoInput.value;
addToLocal();
})
}
})
}
* {
padding: 0;
margin: 0;
}
body {
width: 100vw;
min-height: 100vh;
display: flex;
justify-content: center;
background: linear-gradient(#F00000, #DC281E);
font-family: sans-serif;
}
button:hover {
cursor: pointer;
background-color: #73E831;
}
ul {
list-style-type: none;
/* get rid of bullet points on side of list items */
}
/* common style ends */
/* container */
.container {
min-width: 700px;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
h1 {
color: #fff;
font-size: 3rem;
}
/* todo-form */
.todo-form {
margin: 40px 0px;
}
.todo-input {
width: 250px;
border: none;
outline: none;
border-radius: 5px;
padding: 10px;
margin-right: 10px;
font-size: 1rem;
}
.add-button {
background-color: #0000ff;
color: #fff;
border: none;
outline: none;
border-radius: 5px;
padding: 7px;
font-size: 1.2rem;
}
/* todo-form style ends */
/* todo-items */
.todo-items {
min-width: 350px;
}
/* each li with class="item" */
.item {
background-color: #fff;
padding: 10px;
font-size: 1.1rem;
}
.item:first-child {
border-top-left-radius: 7px;
border-top-right-radius: 7px;
}
.item:last-child {
border-bottom-left-radius: 7px;
border-bottom-right-radius: 7px;
}
/* item style end */
.checkbox {
margin-right: 10px;
}
.delete-button {
float: right;
background-color: #dc143c;
border: none;
outline: none;
border-radius: 7px;
padding: 2px 5px;
margin-left: 10px;
font-size: 1.1rem;
font-weight: 550;
}
.edit-button {
float: right;
background-color: blue;
border: none;
outline: none;
border-radius: 7px;
padding: 2px 5px;
margin-left: 3px;
font-size: 1.1rem;
font-weight: 550;
}
/* applied when the todo item is checked */
.checked {
text-decoration: line-through;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Todo List</title>
</head>
<body>
<div class="container">
<h1>Todo</h1>
<form class="todo-form">
<input type="text" class="todo-input" placeholder="Add a Todo...">
<button type="submit" class="add-button">Add</button>
</form>
<ul class="todo-items">
<!-- dummy item -->
<li class="item" data-key="1594003133171">
<input class="checkbox" type="checkbox">
Go to Gym
<button class="delete-button">X</button>
</li>
</ul>
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
您正在为每个选择创建一个新的 'submit' 事件侦听器并且从不清除它们。
每次选择都会向现有事件侦听器添加一个新的事件侦听器
查看编辑方法的变化,或查看jsfiddle
const todoForm = document.querySelector('.todo-form');
// select the input box
const todoInput = document.querySelector('.todo-input');
// select the <ul> with class="todo-items"
const todoItemsList = document.querySelector('.todo-items');
const butt = document.querySelector('.add-button');
let todos = [];
todoForm.addEventListener('submit', (e) => {
if(butt.innerHTML === "Add"){
console.log("Add");
e.preventDefault();
AddTo(todoInput.value);
console.log(todoInput.value);}
});
function AddTo(item){
console.log(item);
if(item!= ''){
const todo = {
id : Date.now(),
name : item,
completed : false
}
todos.push(todo);
addToLocal();
todoInput.value = '';
}
}
function renderTo(){
todoItemsList.innerHTML = '';
todos.forEach((item) => {
const checked = item.completed ? 'checked' : null;
const li = document.createElement('li');
li.setAttribute('class','item');
li.setAttribute('data-key', item.id);
if(item.completed == true){
li.classList.add('checked');
}
li.innerHTML = `<input type = "checkbox" class = "checkbox" ${checked}> ${item.name} <button class = "delete-button">X</button> <button class = "edit-button">E</button>`;
todoItemsList.append(li);
})
}
function addToLocal(){
localStorage.setItem('todos', JSON.stringify(todos));
renderTo();
}
function getFromLocal(){
const reference = localStorage.getItem('todos');
if(reference){
todos = JSON.parse(reference);
renderTo()
}
}
getFromLocal();
todoItemsList.addEventListener('click', (e) => {
if(e.target.type === 'checkbox'){
toggle(e.target.parentElement.getAttribute('data-key'));
}
if(e.target.classList.contains('delete-button')){
del(e.target.parentElement.getAttribute('data-key'));
}
if(e.target.classList.contains('edit-button')){
edit(e.target.parentElement.getAttribute('data-key'));
}
})
function toggle(id){
todos.forEach((item) => {
if(item.id == id){
item.completed = !item.completed;
}
});
addToLocal();
}
function del(id){
todos = todos.filter((item) => {
return item.id != id;
});
addToLocal();
}
function edit(id){
console.log(id)
butt.innerHTML = "Edit";
todos.forEach((item) => {
if(item.id == id){
todoInput.value = item.name;
console.log('in for', item);
const listener = (e) => {
e.preventDefault();
console.log('submit', item);
item.name = todoInput.value;
addToLocal();
todoForm.removeEventListener('submit', listener) //<-- clear listener when its done
}
todoForm.addEventListener('submit', listener)
}
})
}
* {
padding: 0;
margin: 0;
}
body {
width: 100vw;
min-height: 100vh;
display: flex;
justify-content: center;
background: linear-gradient(#F00000, #DC281E);
font-family: sans-serif;
}
button:hover {
cursor: pointer;
background-color: #73E831;
}
ul {
list-style-type: none;
/* get rid of bullet points on side of list items */
}
/* common style ends */
/* container */
.container {
min-width: 700px;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
h1 {
color: #fff;
font-size: 3rem;
}
/* todo-form */
.todo-form {
margin: 40px 0px;
}
.todo-input {
width: 250px;
border: none;
outline: none;
border-radius: 5px;
padding: 10px;
margin-right: 10px;
font-size: 1rem;
}
.add-button {
background-color: #0000ff;
color: #fff;
border: none;
outline: none;
border-radius: 5px;
padding: 7px;
font-size: 1.2rem;
}
/* todo-form style ends */
/* todo-items */
.todo-items {
min-width: 350px;
}
/* each li with class="item" */
.item {
background-color: #fff;
padding: 10px;
font-size: 1.1rem;
}
.item:first-child {
border-top-left-radius: 7px;
border-top-right-radius: 7px;
}
.item:last-child {
border-bottom-left-radius: 7px;
border-bottom-right-radius: 7px;
}
/* item style end */
.checkbox {
margin-right: 10px;
}
.delete-button {
float: right;
background-color: #dc143c;
border: none;
outline: none;
border-radius: 7px;
padding: 2px 5px;
margin-left: 10px;
font-size: 1.1rem;
font-weight: 550;
}
.edit-button {
float: right;
background-color: blue;
border: none;
outline: none;
border-radius: 7px;
padding: 2px 5px;
margin-left: 3px;
font-size: 1.1rem;
font-weight: 550;
}
/* applied when the todo item is checked */
.checked {
text-decoration: line-through;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Todo List</title>
</head>
<body>
<div class="container">
<h1>Todo</h1>
<form class="todo-form">
<input type="text" class="todo-input" placeholder="Add a Todo...">
<button type="submit" class="add-button">Add</button>
</form>
<ul class="todo-items">
<!-- dummy item -->
<li class="item" data-key="1594003133171">
<input class="checkbox" type="checkbox">
Go to Gym
<button class="delete-button">X</button>
</li>
</ul>
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
我试图在原版 JS 中制作待办事项列表。有一个添加按钮可以在列表中添加项目。当为特定项目选择编辑选项时,添加按钮变为编辑并且输入框接受编辑的值。
当我编辑第一个项目时,它工作正常。但是当我编辑第二个项目时,第一个和第二个项目的值都会发生变化。编辑第三项时也是如此,第二项和第一项的值也会发生变化。我不确定为什么会这样。
const todoForm = document.querySelector('.todo-form');
// select the input box
const todoInput = document.querySelector('.todo-input');
// select the <ul> with class="todo-items"
const todoItemsList = document.querySelector('.todo-items');
const butt = document.querySelector('.add-button');
let todos = [];
todoForm.addEventListener('submit', (e) => {
if(butt.innerHTML === "Add"){
console.log("Add");
e.preventDefault();
AddTo(todoInput.value);
console.log(todoInput.value);}
});
function AddTo(item){
console.log(item);
if(item!= ''){
const todo = {
id : Date.now(),
name : item,
completed : false
}
todos.push(todo);
addToLocal();
todoInput.value = '';
}
}
function renderTo(){
todoItemsList.innerHTML = '';
todos.forEach((item) => {
const checked = item.completed ? 'checked' : null;
const li = document.createElement('li');
li.setAttribute('class','item');
li.setAttribute('data-key', item.id);
if(item.completed == true){
li.classList.add('checked');
}
li.innerHTML = `<input type = "checkbox" class = "checkbox" ${checked}> ${item.name} <button class = "delete-button">X</button> <button class = "edit-button">E</button>`;
todoItemsList.append(li);
})
}
function addToLocal(){
localStorage.setItem('todos', JSON.stringify(todos));
renderTo();
}
function getFromLocal(){
const reference = localStorage.getItem('todos');
if(reference){
todos = JSON.parse(reference);
renderTo()
}
}
getFromLocal();
todoItemsList.addEventListener('click', (e) => {
if(e.target.type === 'checkbox'){
toggle(e.target.parentElement.getAttribute('data-key'));
}
if(e.target.classList.contains('delete-button')){
del(e.target.parentElement.getAttribute('data-key'));
}
if(e.target.classList.contains('edit-button')){
edit(e.target.parentElement.getAttribute('data-key'));
}
})
function toggle(id){
todos.forEach((item) => {
if(item.id == id){
item.completed = !item.completed;
}
});
addToLocal();
}
function del(id){
todos = todos.filter((item) => {
return item.id != id;
});
addToLocal();
}
function edit(id){
butt.innerHTML = "Edit";
todos.forEach((item) => {
if(item.id == id){
todoInput.value = item.name;
console.log(item);
todoForm.addEventListener('submit', (e) => {
e.preventDefault();
console.log(item);
item.name = todoInput.value;
addToLocal();
})
}
})
}
* {
padding: 0;
margin: 0;
}
body {
width: 100vw;
min-height: 100vh;
display: flex;
justify-content: center;
background: linear-gradient(#F00000, #DC281E);
font-family: sans-serif;
}
button:hover {
cursor: pointer;
background-color: #73E831;
}
ul {
list-style-type: none;
/* get rid of bullet points on side of list items */
}
/* common style ends */
/* container */
.container {
min-width: 700px;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
h1 {
color: #fff;
font-size: 3rem;
}
/* todo-form */
.todo-form {
margin: 40px 0px;
}
.todo-input {
width: 250px;
border: none;
outline: none;
border-radius: 5px;
padding: 10px;
margin-right: 10px;
font-size: 1rem;
}
.add-button {
background-color: #0000ff;
color: #fff;
border: none;
outline: none;
border-radius: 5px;
padding: 7px;
font-size: 1.2rem;
}
/* todo-form style ends */
/* todo-items */
.todo-items {
min-width: 350px;
}
/* each li with class="item" */
.item {
background-color: #fff;
padding: 10px;
font-size: 1.1rem;
}
.item:first-child {
border-top-left-radius: 7px;
border-top-right-radius: 7px;
}
.item:last-child {
border-bottom-left-radius: 7px;
border-bottom-right-radius: 7px;
}
/* item style end */
.checkbox {
margin-right: 10px;
}
.delete-button {
float: right;
background-color: #dc143c;
border: none;
outline: none;
border-radius: 7px;
padding: 2px 5px;
margin-left: 10px;
font-size: 1.1rem;
font-weight: 550;
}
.edit-button {
float: right;
background-color: blue;
border: none;
outline: none;
border-radius: 7px;
padding: 2px 5px;
margin-left: 3px;
font-size: 1.1rem;
font-weight: 550;
}
/* applied when the todo item is checked */
.checked {
text-decoration: line-through;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Todo List</title>
</head>
<body>
<div class="container">
<h1>Todo</h1>
<form class="todo-form">
<input type="text" class="todo-input" placeholder="Add a Todo...">
<button type="submit" class="add-button">Add</button>
</form>
<ul class="todo-items">
<!-- dummy item -->
<li class="item" data-key="1594003133171">
<input class="checkbox" type="checkbox">
Go to Gym
<button class="delete-button">X</button>
</li>
</ul>
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
您正在为每个选择创建一个新的 'submit' 事件侦听器并且从不清除它们。
每次选择都会向现有事件侦听器添加一个新的事件侦听器
查看编辑方法的变化,或查看jsfiddle
const todoForm = document.querySelector('.todo-form');
// select the input box
const todoInput = document.querySelector('.todo-input');
// select the <ul> with class="todo-items"
const todoItemsList = document.querySelector('.todo-items');
const butt = document.querySelector('.add-button');
let todos = [];
todoForm.addEventListener('submit', (e) => {
if(butt.innerHTML === "Add"){
console.log("Add");
e.preventDefault();
AddTo(todoInput.value);
console.log(todoInput.value);}
});
function AddTo(item){
console.log(item);
if(item!= ''){
const todo = {
id : Date.now(),
name : item,
completed : false
}
todos.push(todo);
addToLocal();
todoInput.value = '';
}
}
function renderTo(){
todoItemsList.innerHTML = '';
todos.forEach((item) => {
const checked = item.completed ? 'checked' : null;
const li = document.createElement('li');
li.setAttribute('class','item');
li.setAttribute('data-key', item.id);
if(item.completed == true){
li.classList.add('checked');
}
li.innerHTML = `<input type = "checkbox" class = "checkbox" ${checked}> ${item.name} <button class = "delete-button">X</button> <button class = "edit-button">E</button>`;
todoItemsList.append(li);
})
}
function addToLocal(){
localStorage.setItem('todos', JSON.stringify(todos));
renderTo();
}
function getFromLocal(){
const reference = localStorage.getItem('todos');
if(reference){
todos = JSON.parse(reference);
renderTo()
}
}
getFromLocal();
todoItemsList.addEventListener('click', (e) => {
if(e.target.type === 'checkbox'){
toggle(e.target.parentElement.getAttribute('data-key'));
}
if(e.target.classList.contains('delete-button')){
del(e.target.parentElement.getAttribute('data-key'));
}
if(e.target.classList.contains('edit-button')){
edit(e.target.parentElement.getAttribute('data-key'));
}
})
function toggle(id){
todos.forEach((item) => {
if(item.id == id){
item.completed = !item.completed;
}
});
addToLocal();
}
function del(id){
todos = todos.filter((item) => {
return item.id != id;
});
addToLocal();
}
function edit(id){
console.log(id)
butt.innerHTML = "Edit";
todos.forEach((item) => {
if(item.id == id){
todoInput.value = item.name;
console.log('in for', item);
const listener = (e) => {
e.preventDefault();
console.log('submit', item);
item.name = todoInput.value;
addToLocal();
todoForm.removeEventListener('submit', listener) //<-- clear listener when its done
}
todoForm.addEventListener('submit', listener)
}
})
}
* {
padding: 0;
margin: 0;
}
body {
width: 100vw;
min-height: 100vh;
display: flex;
justify-content: center;
background: linear-gradient(#F00000, #DC281E);
font-family: sans-serif;
}
button:hover {
cursor: pointer;
background-color: #73E831;
}
ul {
list-style-type: none;
/* get rid of bullet points on side of list items */
}
/* common style ends */
/* container */
.container {
min-width: 700px;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
h1 {
color: #fff;
font-size: 3rem;
}
/* todo-form */
.todo-form {
margin: 40px 0px;
}
.todo-input {
width: 250px;
border: none;
outline: none;
border-radius: 5px;
padding: 10px;
margin-right: 10px;
font-size: 1rem;
}
.add-button {
background-color: #0000ff;
color: #fff;
border: none;
outline: none;
border-radius: 5px;
padding: 7px;
font-size: 1.2rem;
}
/* todo-form style ends */
/* todo-items */
.todo-items {
min-width: 350px;
}
/* each li with class="item" */
.item {
background-color: #fff;
padding: 10px;
font-size: 1.1rem;
}
.item:first-child {
border-top-left-radius: 7px;
border-top-right-radius: 7px;
}
.item:last-child {
border-bottom-left-radius: 7px;
border-bottom-right-radius: 7px;
}
/* item style end */
.checkbox {
margin-right: 10px;
}
.delete-button {
float: right;
background-color: #dc143c;
border: none;
outline: none;
border-radius: 7px;
padding: 2px 5px;
margin-left: 10px;
font-size: 1.1rem;
font-weight: 550;
}
.edit-button {
float: right;
background-color: blue;
border: none;
outline: none;
border-radius: 7px;
padding: 2px 5px;
margin-left: 3px;
font-size: 1.1rem;
font-weight: 550;
}
/* applied when the todo item is checked */
.checked {
text-decoration: line-through;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Todo List</title>
</head>
<body>
<div class="container">
<h1>Todo</h1>
<form class="todo-form">
<input type="text" class="todo-input" placeholder="Add a Todo...">
<button type="submit" class="add-button">Add</button>
</form>
<ul class="todo-items">
<!-- dummy item -->
<li class="item" data-key="1594003133171">
<input class="checkbox" type="checkbox">
Go to Gym
<button class="delete-button">X</button>
</li>
</ul>
</div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>