You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数组对象属性无法更新——图书馆应用阅读状态修改问题

问题描述

这是我首次在此发帖,若代码存在不足还请见谅,我会尽力描述问题。
我正在开发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 22:01:00