数组对象属性无法更新——图书馆应用阅读状态修改问题
问题描述
这是我首次在此发帖,若代码存在不足还请见谅,我会尽力描述问题。
我正在开发Odin Project的图书馆应用,目前已实现通过弹窗表单创建对象,并能在页面上正确显示对象的各项值。
我的目标是点击按钮时更新myLibrary数组中的阅读状态(read),目前已实现点击按钮更新按钮文本,但不知如何更新数组中对应对象的read属性。
恳请各位提供建议,感谢您的时间。
现有代码
JavaScript
let myLibrary = []; const registerBook = document.getElementById("registerBook"); const title = document.getElementById("title"); const author = document.getElementById("author"); const pages = document.getElementById("pages"); let read = document.getElementById("read-btn"); let form = document.getElementById("bookForm"); let optionYes = document.getElementById("option-yes"); let optionNo = document.getElementById("option-no"); function openForm() { document.getElementById("bookForm").style.display = "block"; } function closeForm() { document.getElementById("bookForm").style.display = "none"; } registerBook.addEventListener("click", function() { myLibrary.push({ title: title.value, author: author.value, pages: pages.value, read: read.value, }) renderBooks(); console.log(myLibrary); }) function renderBooks() { let bookShelf = document.querySelector('#bookShelf'); let bookCover = document.createElement('div'); bookCover.classList.add('bookCover'); bookShelf.appendChild(bookCover); let deleteCard = document.createElement('div'); deleteCard.classList.add('delete-card'); deleteCard.id = "deleteCard"; bookCover.append(deleteCard); let bookTitleTag = document.createElement('div'); bookTitleTag.classList.add('book-title-tag'); bookCover.append(bookTitleTag); bookTitleTag.textContent = 'Book title:'; let bookTitle = document.createElement('div'); bookTitle.classList.add('book-title'); bookCover.append(bookTitle); let bookAuthorTag = document.createElement('div'); bookAuthorTag.classList.add('book-author-tag'); bookCover.append(bookAuthorTag); bookAuthorTag.textContent = 'Book author:'; let bookAuthor = document.createElement('div'); bookAuthor.classList.add('book-author'); bookCover.append(bookAuthor); let bookPagesTag = document.createElement('div'); bookPagesTag.classList.add('book-pages-tag'); bookCover.append(bookPagesTag); bookPagesTag.textContent = 'No of pages:'; let bookPages = document.createElement('div'); bookPages.classList.add('book-pages'); bookCover.append(bookPages); let bookStatusTag = document.createElement('div'); bookStatusTag.classList.add('book-pages-tag'); bookCover.append(bookStatusTag); bookStatusTag.textContent = 'Have you read the book?:'; let bookStatus = document.createElement('button'); bookStatus.classList.add('book-status-btn'); bookStatus.id = 'book-status-btn'; bookCover.append(bookStatus); bookTitle.textContent = title.value; bookAuthor.textContent = author.value; bookPages.textContent = pages.value; bookStatus.textContent = read.value; /*Book status in card is updated */ bookStatus.addEventListener("click", () => { if (bookStatus.textContent === 'Yes') { bookStatus.textContent = 'No' } else { if (bookStatus.textContent === 'No') { bookStatus.textContent = 'Yes' } } }); /* Trying to update array */ bookStatus.addEventListener("click", () => { if (bookCover.read === 'Yes') { bookCover.read = 'No' } else { if (bookCover.read === 'No') { bookCover.read = 'Yes' } } console.log(myLibrary); }); deleteCard.addEventListener("click", () => { bookShelf.removeChild(bookCover); myLibrary.splice(bookCover, 1); }); }
HTML
<!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"> <link rel="stylesheet" href="styles.css"> <script defer src="index.js"></script> <title>Library</title> </head> <body> <div class="wrapper"> <div class="header"> <div class="logo">Library</div> <div class="buttons"> <div class="add-book-btn" id="addBookBtn" onclick="openForm()">Add Book</div> <!--<div class="login-btn">Log in</div> --> </div> </div> <div class="main"> <div class="form-popup" id="bookForm"> <form action="/action_page.php" onsubmit="event.preventDefault()" class="form-container"> <div class="form-popup-close" onclick="closeForm()"></div> <h1>Add Book</h1> <label for="title"><b>Book title</b></label> <input type="text" id="title" placeholder="Enter book title" name="title" required> <label for="author"><b>Author</b></label> <input type="text" id="author" placeholder="Enter author name" name="author"> <label for="pages"><b>No. of pages</b></label> <input type="number" id="pages" placeholder="Number of pages" name="pages"> <div class="form-bot"> <p>Have you read it?</p> <select name="read" id="read-btn"> <option id="option-yes" value="Yes">Yes</option> <option id="option-no" value="No">No</option> </select> </div> <button type="button" class="btn" id="registerBook" onclick="closeForm()">Register Book</button> </form> </div> <div id="bookShelf"></div> </div> </div> </body> </html>
解决方案
你的核心问题是没有在DOM元素和数组中的对应图书对象之间建立关联,导致点击按钮时找不到要更新的数组元素。按以下步骤修改即可解决:
1. 给图书对象添加唯一标识,关联DOM元素
在创建图书对象时,给每个对象生成唯一id,并绑定到对应的DOM容器上:
// 修改registerBook的点击事件 registerBook.addEventListener("click", function() { // 用时间戳生成唯一id const bookId = Date.now(); const newBook = { id: bookId, title: title.value, author: author.value, pages: pages.value, read: read.value, }; myLibrary.push(newBook); // 将图书对象传入renderBooks,确保DOM渲染的是当前新增的图书 renderBooks(newBook); console.log(myLibrary); });
2. 重构renderBooks函数,绑定标识并同步更新数组
修改renderBooks函数,接收具体图书对象,同时合并点击事件,通过绑定的id找到数组中对应元素更新:
// 修改renderBooks,接收book参数 function renderBooks(book) { let bookShelf = document.querySelector('#bookShelf'); let bookCover = document.createElement('div'); bookCover.classList.add('bookCover'); // 将图书id存入DOM元素的dataset,建立关联 bookCover.dataset.bookId = book.id; bookShelf.appendChild(bookCover); // 以下DOM创建代码保持不变... let deleteCard = document.createElement('div'); deleteCard.classList.add('delete-card'); bookCover.append(deleteCard); let bookTitleTag = document.createElement('div'); bookTitleTag.classList.add('book-title-tag'); bookCover.append(bookTitleTag); bookTitleTag.textContent = 'Book title:'; let bookTitle = document.createElement('div'); bookTitle.classList.add('book-title'); bookCover.append(bookTitle); let bookAuthorTag = document.createElement('div'); bookAuthorTag.classList.add('book-author-tag'); bookCover.append(bookAuthorTag); bookAuthorTag.textContent = 'Book author:'; let bookAuthor = document.createElement('div'); bookAuthor.classList.add('book-author'); bookCover.append(bookAuthor); let bookPagesTag = document.createElement('div'); bookPagesTag.classList.add('book-pages-tag'); bookCover.append(bookPagesTag); bookPagesTag.textContent = 'No of pages:'; let bookPages = document.createElement('div'); bookPages.classList.add('book-pages'); bookCover.append(bookPages); let bookStatusTag = document.createElement('div'); bookStatusTag.classList.add('book-pages-tag'); bookCover.append(bookStatusTag); bookStatusTag.textContent = 'Have you read the book?:'; let bookStatus = document.createElement('button'); bookStatus.classList.add('book-status-btn'); bookCover.append(bookStatus); // 用传入的book对象填充内容,而非直接取表单当前值 bookTitle.textContent = book.title; bookAuthor.textContent = book.author; bookPages.textContent = book.pages; bookStatus.textContent = book.read; // 合并状态按钮的点击事件,同时更新按钮文本和数组 bookStatus.addEventListener("click", () => { const newStatus = bookStatus.textContent === 'Yes' ? 'No' : 'Yes'; bookStatus.textContent = newStatus; // 通过dataset中的bookId找到数组中对应的图书 const targetBookIndex = myLibrary.findIndex(item => item.id === parseInt(bookCover.dataset.bookId)); if (targetBookIndex !== -1) { myLibrary[targetBookIndex].read = newStatus; console.log(myLibrary); } }); // 修复删除逻辑,通过id找到数组元素删除 deleteCard.addEventListener("click", () => { bookShelf.removeChild(bookCover); const targetBookIndex = myLibrary.findIndex(item => item.id === parseInt(bookCover.dataset.bookId)); if (targetBookIndex !== -1) { myLibrary.splice(targetBookIndex, 1); console.log(myLibrary); } }); }
3. 其他细节修复
- 移除重复的
id属性(如deleteCard、book-status-btn),id必须唯一,只用class即可。 - 避免直接依赖表单输入框的当前值渲染图书,确保每次渲染的是新增时的图书数据。
修改后,点击状态按钮时就能精准找到myLibrary中对应的图书对象,同步更新其read属性。
内容的提问来源于stack exchange,提问作者Havhar0
相关产品推荐
相关产品推荐

