问题描述
应用程序演示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",pages: "100",];
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,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",pages: "100",];
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,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();
});
});