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();
});
});
应用程序演示 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();
});
});