如何为数组中的每个对象生成多张卡片?

How to generate multiple card for each object in an array?

@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%;
}

.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;
}

.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 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>

我想为数组中的每个对象生成多张卡片。我面临的问题是,每次添加新对象时,都会生成数组中现有对象的重复卡片。有什么方法可以仅通过使用 vanilla js 来修复它吗?

https://i.stack.imgur.com/EsApw.png

const form = document.getElementById('input-form');
const formButton = document.getElementById('add-form');
const formView = document.querySelector('.form-card')
const bookList = document.querySelector('.books-wrapper');
const bookCard = document.querySelector('.book-card');

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();
  this.reset();
  console.table(myLibrary)
};

function populateBooks(myLib, bookView) {
  myLib.forEach((book, i) => {
    const card = `<div class="book-card" data-index=${i}>
                            <div class="card-info-wrapper">
                                 <h2>${book.title}</h2>
                                 <h3>${book.author}</h3>
                                 <h4>${book.pages} Pages</h4>
                                 <p>${book.info()}</p>
                                     <div class="button">
                                        Remove
                                     </div>
                            </div>
                        </div>`
    const element = document.createElement('div');
    element.innerHTML = card;
    bookView.appendChild(element.firstChild);

  });

};
function formDisplay() {
formView.classList.toggle('toggle-on');
};
formButton.addEventListener('click', formDisplay);
populateBooks(myLibrary, bookList);
[enter image description here][1]

您再次将整个图书馆的图书附加到已经填充的 div。

您的解决方案很简单,只需在再次附加所有内容之前清理 div 本书。

这里是你的 JS 修改和工作:

const form = document.getElementById('input-form');
const formButton = document.getElementById('add-form');
const formView = document.querySelector('.form-card')
const bookList = document.querySelector('.books-wrapper');
const bookCard = document.querySelector('.book-card');

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();
  this.reset();
  console.table(myLibrary)
};

function populateBooks(myLib, bookView) {
  bookList.innerHTML = "";
  myLib.forEach((book, i) => {
    const card = `<div class="book-card" data-index=${i}>
                            <div class="card-info-wrapper">
                                 <h2>${book.title}</h2>
                                 <h3>${book.author}</h3>
                                 <h4>${book.pages} Pages</h4>
                                 <p>${book.info()}</p>
                                     <div class="button">
                                        Remove
                                     </div>
                            </div>
                        </div>`
    const element = document.createElement('div');
    element.innerHTML = card;
    bookView.appendChild(element.firstChild);

  });

}

document.addEventListener("DOMContentLoaded", function() {
    form.addEventListener("submit", function(e) {
        addToLibrary(e)
    });
});

我修改了一些部分以使其在本地工作,因为您没有发布您的 HTML。

我添加的行是:

bookList.innerHTML = "";

就在 populateBooks 函数的开头。

编辑:使用更新后的代码使其工作,Here is the JSFiddle with your full code modified to working.

事情是添加命令 document.querySelectorAll('.book-card').forEach(e => e.remove()); 以删除 div 中所有已经呈现的书籍,因此当您 运行 您的函数时,它只会删除书籍然后再次正确渲染。