Javascript ES6 书单错误

Javascript ES6 Booklist bug

应用程序演示 https://scannerbug.netlify.app/

这是一个简单的网络应用程序,可根据 API 检查扫描的条形码,并将返回的数据添加到书单中。

问题是我第一次扫描一本书时,只添加了一本,第二次添加了两本书(这样变成了三本书),第三次添加了三本书(这样变成了六本书)在列表中)。这样,当我只扫描三本书时,列表中就有 6 本书。

谁能帮帮我?如果您无法理解我的代码中的某些内容,我会提供所需的任何信息。

Pastebin JS 代码:https://pastebin.com/dj7Pi1JE

//SWIPER SETTING
document.addEventListener("DOMContentLoaded", () => {
    const swiper = new Swiper(".swiper-container", {
        effect: "coverflow",
        grabCursor: true,
        centeredSlides: true,
        slidesPerView: "auto",
        coverflowEffect: {
            rotate: 60,
            stretch: 0,
            depth: 150,
            modifier: 1,
            slideShadows: true,
        },
    });
});
//BOOK CLASS
 
class Book {
    constructor(url, cover, title, author, pages, isbn) {
        this.url = url;
        this.cover = cover;
        this.title = title;
        this.author = author;
        this.pages = pages;
        this.isbn = isbn;
    }
}
 
//UI CLASS
class UI {
    static displayBooks() {
        // let swiper = document.querySelector(".swiper-container").swiper;
        // swiper.removeAllSlides();
        const storedBooks = [
            {
                url: "www.google.com",
                title: "Test Title",
                author: "Test Author",
                pages: "230",
                isbn: "9778621466124",
            },
            {
                url: "www.isbndb.com",
                title: "Test Title",
                author: "Test Author",
                pages: "100",
                isbn: "9778621466124",
            },
        ];
 
        const books = storedBooks;
 
        books.forEach((book) => UI.addBookToList(book));
    }
 
    static addBookToList(book) {
        //INIT SWIPER ONLY AFTER ADDING BOOKS
        let swiper = document.querySelector(".swiper-container").swiper;
 
        swiper.appendSlide(`
        <div class="swiper-slide">
            <div class="book-cover">
                <img src="${book.cover}" alt="" />
            </div>
            <div class="book-info">
                <h2 class="book-title">${book.title}</h2>
                <h3 class="book-author">By ${book.author}</h3>
                <p class="book-pages">Pages: ${book.pages}</p>
                <p>ISBN: ${book.isbn}</p>
            </div>
 
            <div class="cta-buttons">
                <a href="${book.url}" class="read-more btn" target="_blank">Read More</a>
                <a href="#" class="delete btn">Remove Book</a>
            </div>
        </div>
        `);
 
        swiper.update();
    }
 
    static deleteBook(element) {
        if (element.classList.contains("delete")) {
            element.parentElement.parentElement.remove();
        }
 
        //INIT SWIPER ONLY AFTER ADDING BOOKS
        let swiper = document.querySelector(".swiper-container").swiper;
        swiper.update();
    }
 
    static clearFields() {
        document.querySelector("#result-form").reset();
    }
}
// STORAGE CLASS
 
//EVENT: DISPLAY BOOKS
document.addEventListener("DOMContentLoaded", UI.displayBooks);
//EVENT ADD A BOOK
function getMovies(searchText) {
    axios
        .get(
            `https://openlibrary.org/api/books?bibkeys=ISBN:${searchText}&format=json&jscmd=data`
        )
        .then((response) => {
            console.log(response);
            let path = `ISBN:${searchText}`;
            let data = response.data[`${path}`];
 
            let cover;
            if (data.cover) {
                cover = data.cover.medium;
            } else {
                cover = "./imgs/book-cover-placeholder.png";
            }
            let url = data.url;
            let title = data.title;
            let author = data.authors[0].name;
            let pages = data.number_of_pages;
            let isbn = searchText;
 
            const book = new Book(url, cover, title, author, pages, isbn);
 
            UI.addBookToList(book);
        })
        .catch((err) => {
            console.log(err);
        });
}
 
// EVENT: REMOVE A BOOK
document.querySelector(".swiper-wrapper").addEventListener("click", (e) => {
    UI.deleteBook(e.target);
});
 
//SCANNER CODE
document.getElementById("start-button").addEventListener("click", function () {
    document.getElementById("search-input").value = "";
    let selectedDeviceId;
    const codeReader = new ZXing.BrowserBarcodeReader();
    console.log("ZXing code reader initialized");
 
    //GET THE VIDEO DEVICE
    codeReader
        .getVideoInputDevices()
        .then((videoInputDevices) => {
            const sourceSelect = document.getElementById("sourceSelect");
            selectedDeviceId = videoInputDevices[0].deviceId;
            if (videoInputDevices.length > 1) {
                videoInputDevices.forEach((element) => {
                    const sourceOption = document.createElement("option");
                    sourceOption.text = element.label;
                    sourceOption.value = element.deviceId;
                    sourceSelect.appendChild(sourceOption);
                });
 
                sourceSelect.onchange = () => {
                    selectedDeviceId = sourceSelect.value;
                };
 
                // const sourceSelectPanel = document.getElementById("sourceSelectPanel");
                // sourceSelectPanel.style.display = "block";
            }
 
            //DECODE BARCODE FROM CAMERA
            (() => {
                codeReader
                    .decodeOnceFromVideoDevice(selectedDeviceId, "video")
                    .then((result) => {
                        let searchText = result.text;
 
                        console.log(result);
                        document.getElementById("search-input").value = searchText;
 
                        //GET MOVIES WHEN ADD BUTTON IS CLICKED
                        document
                            .getElementById("add-button")
                            .addEventListener("click", () => {
                                getMovies(searchText);
 
                                UI.clearFields();
                            });
                    })
                    .catch((err) => {
                        console.error(err);
                    });
            })();
 
            document.getElementById("stop-button").addEventListener("click", () => {
                codeReader.reset();
                console.log("Reset.");
            });
        })
        .catch((err) => {
            console.error(err);
        });
});

问题可能是因为以下部分代码的位置:

document
    .getElementById("add-button")
    .addEventListener("click", () => {
        getMovies(searchText);
 
        UI.clearFields();
    });

此代码片段会在 #add-button 元素 每次 运行 时,即每次扫描后添加一个事件侦听器。

要使您的代码正常工作,请将其移至顶级 DOMContentLoaded 侦听器,并将其更改为以下内容:

document
    .getElementById("add-button")
    .addEventListener("click", () => {
        const searchText = document.getElementById("search-input").value;
        if(!searchText) return;
        
        getMovies(searchText);
 
        UI.clearFields();
    });

所以,你应该有这样的东西:

//SWIPER SETTING
document.addEventListener("DOMContentLoaded", () => {
    const swiper = new Swiper(".swiper-container", {
        effect: "coverflow",
        grabCursor: true,
        centeredSlides: true,
        slidesPerView: "auto",
        coverflowEffect: {
            rotate: 60,
            stretch: 0,
            depth: 150,
            modifier: 1,
            slideShadows: true,
        },
    });
});
//BOOK CLASS
 
class Book {
    constructor(url, cover, title, author, pages, isbn) {
        this.url = url;
        this.cover = cover;
        this.title = title;
        this.author = author;
        this.pages = pages;
        this.isbn = isbn;
    }
}
 
//UI CLASS
class UI {
    static displayBooks() {
        // let swiper = document.querySelector(".swiper-container").swiper;
        // swiper.removeAllSlides();
        const storedBooks = [
            {
                url: "www.google.com",
                title: "Test Title",
                author: "Test Author",
                pages: "230",
                isbn: "9778621466124",
            },
            {
                url: "www.isbndb.com",
                title: "Test Title",
                author: "Test Author",
                pages: "100",
                isbn: "9778621466124",
            },
        ];
 
        const books = storedBooks;
 
        books.forEach((book) => UI.addBookToList(book));
    }
 
    static addBookToList(book) {
        //INIT SWIPER ONLY AFTER ADDING BOOKS
        let swiper = document.querySelector(".swiper-container").swiper;
 
        swiper.appendSlide(`
        <div class="swiper-slide">
            <div class="book-cover">
                <img src="${book.cover}" alt="" />
            </div>
            <div class="book-info">
                <h2 class="book-title">${book.title}</h2>
                <h3 class="book-author">By ${book.author}</h3>
                <p class="book-pages">Pages: ${book.pages}</p>
                <p>ISBN: ${book.isbn}</p>
            </div>
 
            <div class="cta-buttons">
                <a href="${book.url}" class="read-more btn" target="_blank">Read More</a>
                <a href="#" class="delete btn">Remove Book</a>
            </div>
        </div>
        `);
 
        swiper.update();
    }
 
    static deleteBook(element) {
        if (element.classList.contains("delete")) {
            element.parentElement.parentElement.remove();
        }
 
        //INIT SWIPER ONLY AFTER ADDING BOOKS
        let swiper = document.querySelector(".swiper-container").swiper;
        swiper.update();
    }
 
    static clearFields() {
        document.querySelector("#result-form").reset();
    }
}
// STORAGE CLASS
 
//EVENT: DISPLAY BOOKS
document.addEventListener("DOMContentLoaded", UI.displayBooks);
//EVENT ADD A BOOK
function getMovies(searchText) {
    axios
        .get(
            `https://openlibrary.org/api/books?bibkeys=ISBN:${searchText}&format=json&jscmd=data`
        )
        .then((response) => {
            console.log(response);
            let path = `ISBN:${searchText}`;
            let data = response.data[`${path}`];
 
            let cover;
            if (data.cover) {
                cover = data.cover.medium;
            } else {
                cover = "./imgs/book-cover-placeholder.png";
            }
            let url = data.url;
            let title = data.title;
            let author = data.authors[0].name;
            let pages = data.number_of_pages;
            let isbn = searchText;
 
            const book = new Book(url, cover, title, author, pages, isbn);
 
            UI.addBookToList(book);
        })
        .catch((err) => {
            console.log(err);
        });
}
 
// EVENT: REMOVE A BOOK
document.querySelector(".swiper-wrapper").addEventListener("click", (e) => {
    UI.deleteBook(e.target);
});
 
//SCANNER CODE
document.getElementById("start-button").addEventListener("click", function () {
    document.getElementById("search-input").value = "";
    let selectedDeviceId;
    const codeReader = new ZXing.BrowserBarcodeReader();
    console.log("ZXing code reader initialized");
 
    //GET THE VIDEO DEVICE
    codeReader
        .getVideoInputDevices()
        .then((videoInputDevices) => {
            const sourceSelect = document.getElementById("sourceSelect");
            selectedDeviceId = videoInputDevices[0].deviceId;
            if (videoInputDevices.length > 1) {
                videoInputDevices.forEach((element) => {
                    const sourceOption = document.createElement("option");
                    sourceOption.text = element.label;
                    sourceOption.value = element.deviceId;
                    sourceSelect.appendChild(sourceOption);
                });
 
                sourceSelect.onchange = () => {
                    selectedDeviceId = sourceSelect.value;
                };
 
                // const sourceSelectPanel = document.getElementById("sourceSelectPanel");
                // sourceSelectPanel.style.display = "block";
            }
 
            //DECODE BARCODE FROM CAMERA
            (() => {
                codeReader
                    .decodeOnceFromVideoDevice(selectedDeviceId, "video")
                    .then((result) => {
                        let searchText = result.text;
 
                        console.log(result);
                        document.getElementById("search-input").value = searchText;
                    })
                    .catch((err) => {
                        console.error(err);
                    });
            })();
 
            document.getElementById("stop-button").addEventListener("click", () => {
                codeReader.reset();
                console.log("Reset.");
            });
        })
        .catch((err) => {
            console.error(err);
        });
});

document.addEventListener('DOMContentLoaded', () => {
    //GET MOVIES WHEN ADD BUTTON IS CLICKED
    document
        .getElementById("add-button")
        .addEventListener("click", () => {
            const searchText = document.getElementById("search-input").value;
            if(!searchText) return;
    
            getMovies(searchText);
    
            UI.clearFields();
        });
});