addEventListener 在第一次执行后停止

时间:2021-04-18 19:26:20

标签: javascript html css

我当前的 JS 项目遇到了问题。这是一个简单的库,用户可以在其中输入信息并将其吐出到页面上。我有一个添加到每个新 div 的删除按钮,我已将事件侦听器添加到按钮中。当我点击删除时,它会删除第一个 - 但就是这样。如果我想删除不止一本书,它就会停止工作。

我认为我的问题是我如何定位分配给每个 div 的数据集/索引值,但我不确定。我尝试过 for 循环、for each 等,但似乎无法弄清楚。

任何帮助将不胜感激。

const book1 = new Book('inserttitlehere', 'His name?', 63, false)
const book2 = new Book('kill bill', 'author2', 653, false)
const book3 = new Book('oh yeah baby', 'author3', 323, false)
const book4 = new Book('kill me now', 'author4', 132, true)
library.push(book1, book2, book3, book4)

// Book constructor
function Book(title, author, pages, completed) {
  this.title = title
  this.author = author
  this.pages = pages
  this.completed = completed
}

const main = document.querySelector('main');
const form = document.querySelector('.form');


//Function to add books to the DOM 
function displayBooks() {
  let dataIndex = 0;
  main.innerHTML = '';
  library.forEach(book => {
    const bookElement = document.createElement('div')
    bookElement.classList.add('book');
    bookElement.setAttribute('data-index', dataIndex);

    bookElement.innerHTML = `
    <h3> ${book.title} </h3>
    <p> Author: ${book.author}</p>
    <p> Pages: ${book.pages}</p>
    Completed: <input type="checkbox"> ${book.completed} <br>
    <button class="delete">Delete</button>
    `
    main.appendChild(bookElement);
    dataIndex++;
  })
}
displayBooks();

//Add new book to library
function addBookToLibrary(title, author, pages, completed) {
  const newBook = new Book(title, author, pages, completed)
  library.push(newBook);
}

//Deleting a book from the array
let deleteBtns = document.querySelectorAll('.book .delete');

deleteBtns.forEach(button => {
  button.addEventListener('click', () => {
    const index = button.parentNode.dataset['data-index'];
    deleteBook(index);
  })
});

function deleteBook(index) {
  library.splice(index, 1);
  displayBooks();
}


form.addEventListener('submit', (e) => {
  e.preventDefault();
  const title = document.querySelector('#title').value;
  const author = document.querySelector('#author').value;
  const pages = document.querySelector('#pages').value;
  addBookToLibrary(title, author, pages, false);
  document.forms[0].reset();
})

console.log(library);
console.log(deleteBtns);
!DOCTYPE html>
<html lang="en">

<head>
  <link rel="stylesheet" href="style.css">
  <title>Library</title>
</head>

<body>
  <nav>
    <h1>Library</h1>
    <button class="add-book-btn">NEW BOOK</button>
  </nav>
  <main></main>

  <div class="modal">
    <form class="form">
      <p class="close"></p>
      <h2>Add Book</h2>
      <div class="user-input">
        <label for="">Title</label><br>
        <input type="text" id="title" required>
      </div>
      <div class="user-input">
        <label for="">Author</label><br>
        <input type="text" id="author" required>
      </div>
      <div class="user-input">
        <label for="">Pages</label><br>
        <input type="number" id="pages" required>
      </div>
      <div class="user-input">
        <label for="">Read?</label>
        <input type="checkbox" id="read">
      </div>
      <button type="submit" id="submit">Submit</button>
    </form>
  </div>

  <script src="script.js"></script>
</body>

</html>

2 个答案:

答案 0 :(得分:3)

当您构建这样的应用时,通常最好删除不相关的部分,例如表单及其所有相关功能,以便处理其中的特定部分,例如这些用户交互。

>

这是一个缩小版本,采用完全不同的方法,在您创建书籍元素时分别向它们添加事件侦听器。

然后不用担心索引,使用数组方法在库中查找 book 对象。因此,与其在删除元素时重建所有元素,不如简单地同时删除数组中的元素和对象。

它被分解成更小的函数,例如 addBookEvents(),然后在每个不同的事件处理程序中使用 Array.prototype.find()Array.prototype.findIndex() 来修改库。

您为了更改索引而重建所有元素的方法不是很可扩展或效率不高。为了创建此处使用的库数组,我只使用了您的 library.push(book1,book2...),然后运行 ​​console.log(JSON.stringify(library)) 并将其粘贴到此代码中以使其在此阶段保持精简。

请注意,我将元素上的 data-index 更改为 data-title,并假设标题在数组中是唯一的。然后允许搜索数组以找到特定的书对象。在标题重复的情况下,使用独特的图书 id 更可靠

const main = document.getElementById('books-list')

library.forEach(createBookElement)

function handleDeleteClick(event) {
  const bookElem = event.target.closest('.book');
  const title = bookElem.dataset.title;
  bookElem.remove();
  removeFromLibrary(title)
  console.log(title)
}

function handleCompleteChange(event){
    const bookElem = event.target.closest('.book');
    const title = bookElem.dataset.title;
    const checked = event.target.checked;
    toggleLibraryComplete(title, checked)

}

function removeFromLibrary(title) {
  const idx = library.findIndex(book => book.title === title);
  if (idx > -1) {
    library.splice(idx, 1);
    console.log('library length =', library.length)
  }
}

function toggleLibraryComplete(title, checked){
     const book = library.find(book => book.title === title);
     book.completed = checked;
     console.log(JSON.stringify(book))
}

function addBookEvents(bookElement){
   const button = bookElement.querySelector('.delete');  
   button.addEventListener('click', handleDeleteClick);
   const checkbox = bookElement.querySelector('.book-complete');
   checkbox.addEventListener('change', handleCompleteChange);
}



function createBookElement(book) {
  const bookElement = document.createElement('div')
  bookElement.classList.add('book');
  bookElement.setAttribute('data-title', book.title);

  bookElement.innerHTML = `
    <h3> ${book.title} </h3>
    <p> Author: ${book.author}</p>
    <p> Pages: ${book.pages}</p>
    Completed: <input class="book-complete" type="checkbox" ${book.completed && 'checked'}> ${book.completed} <br>
    <button class="delete">Delete</button>
    `;
  // add the event listeners for delete and completed 
  addBookEvents(bookElement);
  main.appendChild(bookElement);

}

//console.log(JSON.stringify(library))
<main id="books-list"></main>
<script>
const library =
[{"title":"inserttitlehere","author":"His name?","pages":63,"completed":true},{"title":"kill bill","author":"author2","pages":653,"completed":false},{"title":"oh yeah baby","author":"author3","pages":323,"completed":false},{"title":"kill me now","author":"author4","pages":132,"completed":true}];
</script>

答案 1 :(得分:0)

试试这个:

var library = []

const book1 = new Book('inserttitlehere', 'His name?', 63, false)
const book2 = new Book('kill bill', 'author2', 653, false)
const book3 = new Book('oh yeah baby', 'author3', 323, false)
const book4 = new Book('kill me now', 'author4', 132, true)
library.push(book1, book2, book3, book4)

// Book constructor
function Book(title, author, pages, completed) {
  this.title = title
  this.author = author
  this.pages = pages
  this.completed = completed
}

const main = document.querySelector('main');
const form = document.querySelector('.form');


//Function to add books to the DOM 
function displayBooks() {
  let dataIndex = 0;
  main.innerHTML = '';
  library.forEach(book => {
    const bookElement = document.createElement('div')
    bookElement.classList.add('book');
    bookElement.setAttribute('data-index', dataIndex);

    bookElement.innerHTML = `
    <h3> ${book.title} </h3>
    <p> Author: ${book.author}</p>
    <p> Pages: ${book.pages}</p>
    Completed: <input type="checkbox"> ${book.completed} <br>
    <button class="delete">Delete</button>
    `
    main.appendChild(bookElement);
    dataIndex++;
  })
}
displayBooks();

//Add new book to library
function addBookToLibrary(title, author, pages, completed) {
  const newBook = new Book(title, author, pages, completed)
  library.push(newBook);
  displayBooks();
}

function addListener() {
  //Deleting a book from the array
  let deleteBtns = document.querySelectorAll('.book .delete');

  deleteBtns.forEach(button => {
    button.addEventListener('click', () => {
      const index = button.parentNode.dataset['data-index'];
      deleteBook(index);
    })
  });
}

addListener();

function deleteBook(index) {
  library.splice(index, 1);
  displayBooks();
  addListener();
}

form.addEventListener('submit', (e) => {
  e.preventDefault();
  const title = document.querySelector('#title').value;
  const author = document.querySelector('#author').value;
  const pages = document.querySelector('#pages').value;
  addBookToLibrary(title, author, pages, false);
  document.forms[0].reset();
})
<!DOCTYPE html>
<html lang="en">

<head>
  <link rel="stylesheet" href="style.css">
  <title>Library</title>
</head>

<body>
  <nav>
    <h1>Library</h1>
    <button class="add-book-btn">NEW BOOK</button>
  </nav>
  <main></main>

  <div class="modal">
    <form class="form">
      <p class="close"></p>
      <h2>Add Book</h2>
      <div class="user-input">
        <label for="">Title</label><br>
        <input type="text" id="title" required>
      </div>
      <div class="user-input">
        <label for="">Author</label><br>
        <input type="text" id="author" required>
      </div>
      <div class="user-input">
        <label for="">Pages</label><br>
        <input type="number" id="pages" required>
      </div>
      <div class="user-input">
        <label for="">Read?</label>
        <input type="checkbox" id="read">
      </div>
      <button type="submit" id="submit">Submit</button>
    </form>
  </div>

  <script src="script.js"></script>
</body>

</html>

首先,library 没有定义,所以我在顶部添加了一个数组 library。然后,我解决了这个问题。

问题是每次删除一本书时,deleteBtn 和按钮事件侦听器都会被更改,因为它们引用的按钮被删除。所以,每次删除一本书时,只需重新初始化它们。我通过将它包装在一个函数中并在每次需要时调用它来做到这一点。

请注意,我还在 displayBooks 下添加了额外的 addBookToLibrary 行,以确保在添加图书时“刷新”页面。