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

JavaScript新手求助:实现按钮在read/unread状态间切换

问题描述

我是JavaScript新手,想要实现点击按钮时切换显示“read”或“unread”状态。尝试将readBook函数绑定到按钮onclick事件时出现错误,希望得到帮助。

附上script.js代码如下:

class Book {
  constructor(title, author, read) {
    this.title = title;
    this.author = author;
    this.read = read;

    addBookToLibrary(this);
  }
}

let myLibrary = [];

const table = document.getElementById('libraryTable');

let hiddenForm = document.getElementById('hiddenForm')
//toggles the input form opacity and z-index
function showForm() {
  hiddenForm.classList.toggle('active')
}

function clearInput() {
  inputs = document.getElementsByTagName('input')
  for (let i in inputs) {
    inputs[i].value = ''
  }
}

function createBook() {
  new Book(document.getElementById('title').value,
    document.getElementById('author').value,
    document.getElementById('read').value);
}

const harrypotter = new Book('Harry Potter', 'JK Rowling', 'read')
const stripedpajamas = new Book('The Boy in the Striped pajamas', 'John Boyne', 'read')
const randomBook = new Book('The random book', 'random author', 'read')

function addBookToLibrary(book) {
  myLibrary.push(book);
}

function readBook(Book) {
  let position = 0;

  for (i = 0; i < myLibrary.length; i++) {
    if (Book.title == myLibrary[i].title) {
      position = i;
    }
  }

  if (myLibrary[position].read == 'read') {
    myLibrary[position].read = "unread";
  } else {
    myLibrary[position].read = "read";
  }
  return myLibrary[position].read;
}

function displayBooks() {
  table.textContent = '';

  for (i = 0; i < myLibrary.length; i++) {
    let newRow = table.insertRow(i);
    newRow.insertCell(0).innerText = myLibrary[i].title;
    newRow.insertCell(1).innerText = myLibrary[i].author;
    newRow.insertCell(2).innerHTML = `&lt;button onclick='${i}' class='tableButtons' &gt;${myLibrary[i].read}&lt;/button&gt;`
    newRow.insertCell(2).innerHTML = `&lt;button onclick='removeBook(${i})' class='tableButtons' &gt;Delete&lt;/button&gt;`
  }
}

function removeBook(index) {
  if (index > 1) {
    myLibrary.splice(index, index - 1);
  } else if (index == 1) {
    myLibrary.splice(index, index);
  } else if (index == 0) {
    myLibrary.shift();
  }

}

const displayButton = document.querySelector(".display");

displayButton.addEventListener('click', button => {
  displayBooks();
});
问题分析与修复方案

核心问题梳理

  • 按钮被覆盖:displayBooks中给同一单元格重复赋值,导致切换状态的按钮被删除按钮覆盖,根本无法显示。
  • onclick绑定错误:状态按钮的onclick仅写了${i},未调用readBook函数;且readBook通过title查找书籍位置的逻辑冗余,直接传索引更高效。
  • 全局变量污染:循环中的i未用let/const声明,会成为全局变量,引发逻辑混乱。
  • 删除函数逻辑冗余:removeBook分情况处理的写法没必要,splice(index, 1)即可删除对应位置的单个元素。
  • 输入框清空逻辑错误:用for...in遍历HTMLCollection会拿到非元素属性(如length),导致报错。

修复后的完整代码

class Book {
  constructor(title, author, read) {
    this.title = title;
    this.author = author;
    this.read = read;

    addBookToLibrary(this);
  }
}

let myLibrary = [];

const table = document.getElementById('libraryTable');
let hiddenForm = document.getElementById('hiddenForm')

// 切换表单显示/隐藏
function showForm() {
  hiddenForm.classList.toggle('active')
}

// 清空输入框
function clearInput() {
  const inputs = document.getElementsByTagName('input')
  for (const input of inputs) {
    input.value = ''
  }
}

// 创建新书籍
function createBook() {
  new Book(
    document.getElementById('title').value,
    document.getElementById('author').value,
    document.getElementById('read').value
  );
}

// 初始化测试书籍
const harrypotter = new Book('Harry Potter', 'JK Rowling', 'read')
const stripedpajamas = new Book('The Boy in the Striped pajamas', 'John Boyne', 'read')
const randomBook = new Book('The random book', 'random author', 'read')

// 添加书籍到图书馆
function addBookToLibrary(book) {
  myLibrary.push(book);
}

// 根据索引切换书籍阅读状态
function readBook(index) {
  const book = myLibrary[index];
  book.read = book.read === 'read' ? 'unread' : 'read';
  // 切换后重新渲染列表更新显示
  displayBooks();
}

// 渲染书籍列表
function displayBooks() {
  table.textContent = '';

  for (let i = 0; i < myLibrary.length; i++) {
    const newRow = table.insertRow(i);
    newRow.insertCell(0).innerText = myLibrary[i].title;
    newRow.insertCell(1).innerText = myLibrary[i].author;
    
    // 状态切换按钮单元格
    const statusCell = newRow.insertCell(2);
    statusCell.innerHTML = `<button onclick='readBook(${i})' class='tableButtons'>${myLibrary[i].read}</button>`;
    
    // 删除按钮单元格
    const deleteCell = newRow.insertCell(3);
    deleteCell.innerHTML = `<button onclick='removeBook(${i})' class='tableButtons'>Delete</button>`;
  }
}

// 根据索引删除书籍
function removeBook(index) {
  myLibrary.splice(index, 1);
  // 删除后重新渲染列表
  displayBooks();
}

// 绑定显示按钮事件
const displayButton = document.querySelector(".display");
displayButton.addEventListener('click', () => {
  displayBooks();
});

关键修复说明

  • 按钮显示正常:给状态按钮和删除按钮分配独立单元格,避免覆盖。
  • 状态切换优化:readBook直接接收索引参数,切换状态后自动重新渲染列表更新页面。
  • 变量规范:所有循环变量和局部变量用let/const声明,避免全局污染。
  • 删除逻辑简化:用splice(index, 1)统一处理所有删除场景,逻辑更清晰。
  • 输入清空修复:改用for...of遍历输入框集合,避免遍历到非元素属性引发报错。

内容的提问来源于stack exchange,提问作者CoolGuy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 08:15:46