从对象数组中删除对象的问题



我有一个问题,从对象数组中删除动态创建的dom对象。问题是,当我从数组中删除某些元素时,拼接元素后的其余元素也被删除。据我所知,这是由于下一个元素的索引被更新到它之前的一个,函数一遍又一遍地删除具有相同索引的元素。

我怎么能解决这个问题?(上传的代码包括HTML和CSS)这是推荐的方法来实现这个功能吗?

function populateBooks(myLib, bookView) {
const bookCards = document.querySelectorAll('.book-card')
bookCards.forEach(bookCard => bookList.removeChild(bookCard));
myLib.forEach((book, index) => {
book.id = index;
const cardContent = `<div class="book-card" data-index=${book.id}>
<div class="card-info-wrapper">
<h2>${book.title}</h2>
<h3>${book.author}</h3>
<h4>${book.pages} Pages</h4>
<p>${book.info()}</p>
</div>
<div class="card-menu">
<div class="button" id="remove-btn">
Remove
</div>
</div>
</div>`
const element = document.createElement('div');
element.innerHTML = cardContent;
// element.dataset.indexx = book.id;
bookView.appendChild(element.firstChild);
const cards = document.querySelectorAll('[data-index]');
cards.forEach(card => {
const removeButton = card.querySelector('.button');
removeButton.addEventListener('click', () => {
removeBook(book.id)
})
})
});
};
function removeBook(id) {
console.log('deleting', id);
myLibrary.splice(id, 1);
console.table(myLibrary);
populateBooks(myLibrary, bookList);
}

完整代码

const form = document.getElementById('input-form');
const formButton = document.getElementById('add-form');
const formView = document.querySelector('.form-card')
const bookList = document.querySelector('.books-wrapper');
let myLibrary = [];
let newBook;
function Book(title, author, pages) {
this.title = title;
this.author = author;
this.pages = pages;
this.info = function() {
return `${this.title} is a book by ${this.author}, ${this.pages} pages, not read yet.`
};
};
Book.prototype.read = false;
function addToLibrary(e) {
{
e.preventDefault();
const title = (document.getElementById('title')).value;
const author = (document.getElementById('author')).value;
const pages = (document.getElementById('pages')).value;
newBook = new Book(title, author, pages);
} {
myLibrary.push(newBook);
populateBooks(myLibrary, bookList);
formDisplay();
form.reset();
console.table(myLibrary)
}
};

function populateBooks(myLib, bookView) {
const bookCards = document.querySelectorAll('.book-card')
bookCards.forEach(bookCard => bookList.removeChild(bookCard));
myLib.forEach((book, index) => {
book.id = index;
const cardContent = `<div class="book-card" data-index=${book.id}>
<div class="card-info-wrapper">
<h2>${book.title}</h2>
<h3>${book.author}</h3>
<h4>${book.pages} Pages</h4>
<p>${book.info()}</p>
</div>
<div class="card-menu">
<div class="button" id="remove-btn">
Remove
</div>
</div>
</div>`
const element = document.createElement('div');
element.innerHTML = cardContent;
// element.dataset.indexx = book.id;
bookView.appendChild(element.firstChild);
const cards = document.querySelectorAll('[data-index]');
cards.forEach(card => {
const removeButton = card.querySelector('.button');
removeButton.addEventListener('click', () => {
removeBook(book.id)
})
})
});
};
function removeBook(id) {
console.log('deleting', id);
myLibrary.splice(id, 1);
console.table(myLibrary);
populateBooks(myLibrary, bookList);
}
function formDisplay() {
form.reset();
formView.classList.toggle('toggle-on');
};
const theHobbit = new Book('The Hobbit', 'J.R.R. Tolkien', 295);
myLibrary.push(theHobbit)
const harryPotter = new Book('Harry Potter', 'J.K Rowling', 320);
myLibrary.push(harryPotter)
const sangaf = new Book('The Subtle Art of Not Giving a Fuck', 'Mark Manson', 300)
myLibrary.push(sangaf)
document.addEventListener("DOMContentLoaded", function() {
form.addEventListener("submit", function(e) {
addToLibrary(e)
});
});
formButton.addEventListener('click', formDisplay);

populateBooks(myLibrary, bookList);
@font-face {
font-family: "fanwood";
font-style: normal;
font-weight: normal;
src: url("fonts/Fanwood.otf");
font-display: swap;
}
:root {
--color-primary: #e9e2d7;
--color-primary-alt: #8e6549;
--color-secondary: #d42257;
--color-background: #d2fbf7;
--color-text: #412d86;
--color-light: #fff;
--color-anchor: #3a00ff;
--font-family: "fanwoood";
--font-weight-strong: 500;
--font-size-h1: 4rem;
--font-size-h2: 3rem;
--font-size-h3: 2rem;
--font-size-h4: 1.35rem;
--font-size-text: 1.15rem;
--border-radius: 8px;
}
*,
*::before,
*::after {
box-sizing: border-box;
}

/* Remove default margin */
body,
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
}
html {
overflow-x: hidden;
}

/* Set core body defaults */
body {
font-family: 'fanwood';
min-height: 100vh;
font-size: 100%;
line-height: 1.5;
text-rendering: optimizeSpeed;
overflow-x: hidden;
}

/* Make images easier to work with */
img {
display: block;
max-width: 100%;
}

/* Inherit fonts for inputs and buttons */
input,
button,
textarea,
select {
font: inherit;
}
body {
background-color: var(--color-primary);
}
button {
background-color: var(--color-primary);
border: none;
margin: 0;
}
input {
width: 100%;
margin-bottom: 10px 0;
}
.site-wrapper {
margin: 0 4%;
}
.card-info-wrapper {
margin: 4% 4%;
text-align: left;
}
.card-menu {
align-self: flex-end;
margin: 4% 4%;
}
.header {
color: var(--color-primary);
background-color: var(--color-primary-alt);
height: 84px;
display: flex;
align-items: center;
justify-content: center;
}
.tool-bar {
margin-top: 20px;
}
.tools {
display: flex;
}
.button {
cursor: pointer;
display: inline-flex;
padding: 2px 8px;
color: var(--color-primary-alt);
background-color: var(--color-primary);
}
.button.add {
display: inline-flex;
padding: 2px 8px;
background-color: var(--color-primary-alt);
color: var(--color-primary);
}
.books-wrapper {
margin-top: 20px;
/* border: 1px solid white; */
display: flex;
flex-wrap: wrap;
}
.book-card {
word-wrap: normal;
background-color: var(--color-primary-alt);
color: var(--color-primary);
width: 300px;
height: 350px;
margin-right: 10px;
margin-bottom: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.form-card {
display: none;
word-wrap: normal;
background-color: var(--color-primary-alt);
color: var(--color-primary);
width: 300px;
height: 350px;
margin-right: 10px;
margin-bottom: 10px;
}
.toggle-on {
display: block;
}
<!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>Book</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="header">
<div class="site-wrapper">
<div class="header-logo-container">
<h1>Library</h1>
</div>
</div>
</div>
<div class="tool-bar">
<div class="site-wrapper">
<div class="tools">
<div class="button add" id="add-form">
Add Book
</div>
</div>
</div>
</div>
<div class="books">
<div class="site-wrapper">
<div class="books-wrapper">
<!-- TEMPLATE FOR BOOK CARD -->
<!-- <div class="book-card">
<div class="card-info-wrapper">
<h2>Title</h2>
<h3>Author</h3>
<h4>Pages</h4>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Ipsum fugit officiis animi soluta et, sit aliquid.</p>
</div>
<div class="card-menu">
<div class="button">
Remove
</div>
</div>
</div> -->
<div class="form-card">
<div class="card-info-wrapper">
<form id="input-form">
<label for="title"><h3>Title</h3></label>
<input type="text" id="title" name="title" placeholder="Name of the Book" required>
<label for="author"><h3>Author</h3></label>
<input type="text" id="author" name="author" placeholder="Name of the Author" required>
<label for="pages"><h3>Pages</h3></label>
<input type="number" id="pages" name="pages" placeholder="Number of Pages" required>
<button type="submit" class="button" id="addBook">Add Book</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>

代码的问题是,对于populateBook中添加的每张卡片,您循环所有以前的卡片并添加单击事件侦听器,这意味着第二本书获得此处理程序的2个副本,第三个3等。

而不是这样做,添加一个事件处理程序点击和适当的处理:
document.querySelector(".books-wrapper").addEventListener("click", (e) => {
if(e.target.classList.contains("button")){
const index = e.target.parentElement.parentElement.dataset.index;
removeBook(index);
}    
});

生活的例子:

const form = document.getElementById('input-form');
const formButton = document.getElementById('add-form');
const formView = document.querySelector('.form-card')
const bookList = document.querySelector('.books-wrapper');
let myLibrary = [];
let newBook;
function Book(title, author, pages) {
this.title = title;
this.author = author;
this.pages = pages;
this.info = function() {
return `${this.title} is a book by ${this.author}, ${this.pages} pages, not read yet.`
};
};
Book.prototype.read = false;
function addToLibrary(e) {
{
e.preventDefault();
const title = (document.getElementById('title')).value;
const author = (document.getElementById('author')).value;
const pages = (document.getElementById('pages')).value;
newBook = new Book(title, author, pages);
} {
myLibrary.push(newBook);
populateBooks(myLibrary, bookList);
formDisplay();
form.reset();
console.table(myLibrary)
}
};

function populateBooks(myLib, bookView) {
const bookCards = document.querySelectorAll('.book-card')
bookCards.forEach(bookCard => bookList.removeChild(bookCard));
myLib.forEach((book, index) => {
book.id = index;
const cardContent = `<div class="book-card" data-index=${book.id}>
<div class="card-info-wrapper">
<h2>${book.title}</h2>
<h3>${book.author}</h3>
<h4>${book.pages} Pages</h4>
<p>${book.info()}</p>
</div>
<div class="card-menu">
<div class="button" id="remove-btn">
Remove
</div>
</div>
</div>`
const element = document.createElement('div');
element.innerHTML = cardContent;
// element.dataset.indexx = book.id;
bookView.appendChild(element.firstChild);      
});
};
function removeBook(id) {
console.log('deleting', id);
myLibrary.splice(id, 1);
console.table(myLibrary);
populateBooks(myLibrary, bookList);
}
function formDisplay() {
form.reset();
formView.classList.toggle('toggle-on');
};
const theHobbit = new Book('The Hobbit', 'J.R.R. Tolkien', 295);
myLibrary.push(theHobbit)
const harryPotter = new Book('Harry Potter', 'J.K Rowling', 320);
myLibrary.push(harryPotter)
const sangaf = new Book('The Subtle Art of Not Giving a Fuck', 'Mark Manson', 300)
myLibrary.push(sangaf)
document.addEventListener("DOMContentLoaded", function() {
form.addEventListener("submit", function(e) {
addToLibrary(e)
});

document.querySelector(".books-wrapper").addEventListener("click", (e) => {
if(e.target.classList.contains("button")){
const index = e.target.parentElement.parentElement.dataset.index;
removeBook(index);
}    
})
});
formButton.addEventListener('click', formDisplay);

populateBooks(myLibrary, bookList);
@font-face {
font-family: "fanwood";
font-style: normal;
font-weight: normal;
src: url("fonts/Fanwood.otf");
font-display: swap;
}
:root {
--color-primary: #e9e2d7;
--color-primary-alt: #8e6549;
--color-secondary: #d42257;
--color-background: #d2fbf7;
--color-text: #412d86;
--color-light: #fff;
--color-anchor: #3a00ff;
--font-family: "fanwoood";
--font-weight-strong: 500;
--font-size-h1: 4rem;
--font-size-h2: 3rem;
--font-size-h3: 2rem;
--font-size-h4: 1.35rem;
--font-size-text: 1.15rem;
--border-radius: 8px;
}
*,
*::before,
*::after {
box-sizing: border-box;
}

/* Remove default margin */
body,
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
}
html {
overflow-x: hidden;
}

/* Set core body defaults */
body {
font-family: 'fanwood';
min-height: 100vh;
font-size: 100%;
line-height: 1.5;
text-rendering: optimizeSpeed;
overflow-x: hidden;
}

/* Make images easier to work with */
img {
display: block;
max-width: 100%;
}

/* Inherit fonts for inputs and buttons */
input,
button,
textarea,
select {
font: inherit;
}
body {
background-color: var(--color-primary);
}
button {
background-color: var(--color-primary);
border: none;
margin: 0;
}
input {
width: 100%;
margin-bottom: 10px 0;
}
.site-wrapper {
margin: 0 4%;
}
.card-info-wrapper {
margin: 4% 4%;
text-align: left;
}
.card-menu {
align-self: flex-end;
margin: 4% 4%;
}
.header {
color: var(--color-primary);
background-color: var(--color-primary-alt);
height: 84px;
display: flex;
align-items: center;
justify-content: center;
}
.tool-bar {
margin-top: 20px;
}
.tools {
display: flex;
}
.button {
cursor: pointer;
display: inline-flex;
padding: 2px 8px;
color: var(--color-primary-alt);
background-color: var(--color-primary);
}
.button.add {
display: inline-flex;
padding: 2px 8px;
background-color: var(--color-primary-alt);
color: var(--color-primary);
}
.books-wrapper {
margin-top: 20px;
/* border: 1px solid white; */
display: flex;
flex-wrap: wrap;
}
.book-card {
word-wrap: normal;
background-color: var(--color-primary-alt);
color: var(--color-primary);
width: 300px;
height: 350px;
margin-right: 10px;
margin-bottom: 10px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.form-card {
display: none;
word-wrap: normal;
background-color: var(--color-primary-alt);
color: var(--color-primary);
width: 300px;
height: 350px;
margin-right: 10px;
margin-bottom: 10px;
}
.toggle-on {
display: block;
}
<!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>Book</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="header">
<div class="site-wrapper">
<div class="header-logo-container">
<h1>Library</h1>
</div>
</div>
</div>
<div class="tool-bar">
<div class="site-wrapper">
<div class="tools">
<div class="button add" id="add-form">
Add Book
</div>
</div>
</div>
</div>
<div class="books">
<div class="site-wrapper">
<div class="books-wrapper">
<!-- TEMPLATE FOR BOOK CARD -->
<!-- <div class="book-card">
<div class="card-info-wrapper">
<h2>Title</h2>
<h3>Author</h3>
<h4>Pages</h4>
<p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Ipsum fugit officiis animi soluta et, sit aliquid.</p>
</div>
<div class="card-menu">
<div class="button">
Remove
</div>
</div>
</div> -->
<div class="form-card">
<div class="card-info-wrapper">
<form id="input-form">
<label for="title"><h3>Title</h3></label>
<input type="text" id="title" name="title" placeholder="Name of the Book" required>
<label for="author"><h3>Author</h3></label>
<input type="text" id="author" name="author" placeholder="Name of the Author" required>
<label for="pages"><h3>Pages</h3></label>
<input type="number" id="pages" name="pages" placeholder="Number of Pages" required>
<button type="submit" class="button" id="addBook">Add Book</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>

最新更新