[英]How do I make the event listeners work for the appended elements?
我已經設置了一個購物車,我正在嘗試讓物品添加和刪除物品。 我附加在事件偵聽器上的項目不起作用。 在我的 Javascipt 中,當您單擊購物車按鈕時,我有滑動動畫。 然后我有一個 for 循環,用於將所有輸入字段標記為一個。 然后我有兩個函數,分別是“addtocart”和“remove”,它們是不言自明的
HTML:
<!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>E-Commerce Website</title>
<link rel="stylesheet" href="/fonts/fontawesome-free-5.3.1-web/css/all.css"><link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous"/>
<link rel="stylesheet" href="style.css">
<script src="app.js"async></script>
</head>
<body>
<div class="wrapper">
<div class="p1">
<div class="topnavcont">
<ul class="topleftnav">
<li class="topnavlink">Home</li>
<li class="topnavlink">Shop</li>
</ul>
<h1 class="topnavtitle">The Store</h1>
<div class="navcartcontainer">
<h3 class="totalnumber">3</h3>
<i class="fas fa-shopping-cart" id="cartbtn"></i>
</div>
</div>
<img src="clark-street-mercantile-vC-GqGbakJo-unsplash.jpg" alt="" class="bgimg">
<div class="overlay"></div>
<div class="cartbody">
<i class="fal fa-times" id="closeicon"></i>
<h2 class="carttitle">Shopping Cart</h2>
<ul class="cartitems">
<li class="cartitem"><span class="itemtitle">Shirt1</span><span class="itemprice">$8.99</span><input type="number"class="qinput"id="qinput"><button class="removebtn">Remove</button></li>
<li class="cartitem"><span class="itemtitle">Shirt2</span><span class="itemprice">$8.99</span><input type="number"class="qinput"id="qinput"><button class="removebtn">Remove</button></li>
<li class="cartitem"><span class="itemtitle">Shirt3</span><span class="itemprice">$8.99</span><input type="number" class="qinput" id="qinput"><button class="removebtn">Remove</button></li>
</ul>
<div class="carttotal">Total: $64.66</div>
</div>
</div>
<div class="p2">
<h1 class="p2title">My Shop</h1>
<div class="itemcontainer">
<div class="item">
<img src="clark-street-mercantile-vC-GqGbakJo-unsplash.jpg" alt="" class="item-img">
<h1 class="item-title">Shirt1</h1>
<h3 class="itemprice">$8.99</h3>
<!-- <a href="#" class="atcbtn">Add To Cart</a> -->
<button class="atcbtn">Add To Cart</button>
</div>
<div class="item">
<img src="clark-street-mercantile-vC-GqGbakJo-unsplash.jpg" alt="" class="item-img">
<h1 class="item-title">Shirt2</h1>
<h3 class="itemprice">$8.99</h3>
<!-- <a href="#" class="atcbtn">Add To Cart</a> -->
<button class="atcbtn">Add To Cart</button>
</div>
<div class="item">
<img src="clark-street-mercantile-vC-GqGbakJo-unsplash.jpg" alt="" class="item-img">
<h1 class="item-title">Shirt3</h1>
<h3 class="itemprice">$8.99</h3>
<!-- <a href="#" class="atcbtn">Add To Cart</a> -->
<button class="atcbtn">Add To Cart</button>
</div>
</div>
<div class="itemcontainer2">
<div class="item">
<img src="clark-street-mercantile-vC-GqGbakJo-unsplash.jpg" alt="" class="item-img">
<h1 class="item-title">Shirt4</h1>
<h3 class="itemprice">$8.99</h3>
<!-- <a href="#" class="atcbtn">Add To Cart</a> -->
<button class="atcbtn">Add To Cart</button>
</div>
<div class="item">
<img src="clark-street-mercantile-vC-GqGbakJo-unsplash.jpg" alt="" class="item-img">
<h1 class="item-title">Shirt5</h1>
<h3 class="itemprice">$8.99</h3>
<!-- <a href="#" class="atcbtn">Add To Cart</a> -->
<button class="atcbtn">Add To Cart</button>
</div>
<div class="item">
<img src="clark-street-mercantile-vC-GqGbakJo-unsplash.jpg" alt="" class="item-img">
<h1 class="item-title">Shirt6</h1>
<h3 class="itemprice">$8.99</h3>
<!-- <a href="#" class="atcbtn">Add To Cart</a> -->
<button class="atcbtn">Add To Cart</button>
</div>
</div>
</div>
</div>
</body>
</html>
CSS:
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
::-webkit-scrollbar{
display: none;
}
.wrapper{
overflow-x: hidden;
}
.topnavcont{
padding: 1em 0em;
align-items: center;
height: 10vh;
width: 100vw;
display: flex;
justify-content: space-around;
background-color: white;
box-shadow: rgba(0, 0, 0, 0.10) 0px 3px 6px, rgba(0, 0, 0, 0.20) 0px 3px 6px;
position: fixed;
z-index: 5;
}
.topleftnav{
display: flex;
justify-content: space-between;
width: 10%;
margin-left: -3%;
font-weight: bold;
}
.topleftnav li{
cursor: pointer;
list-style: none;
font-size: 1.05rem;
transition: 0.3s ease;
border-bottom: transparent solid 2px;
}
.topleftnav li:hover{
border-bottom: black solid 2px;
transform: scale(1.1);
}
.topnavtitle{
margin-right: 2.5%;
}
.navcartcontainer{
display: flex;
margin-right: -1%;
}
.topnavcont .totalnumber{
color: black;
padding: 0.2em 0.4em;
border-radius: 50%;
font-size: 1.25rem;
height: fit-content;
/* cursor: pointer; */
font-weight: bold;
}
.topnavcont i{
font-size: 2rem;
margin-left: 0.3em;
cursor: pointer;
transition: 0.4s ease;
}
.topnavcont i:hover{
transform: scale(1.15);
}
.p1{
height: 100vh;
position: relative;
}
.p1 img{
object-fit: cover;
height: 100vh;
width: 100%;
}
.p1 .overlay::after{
content: "";
position: absolute;
top: 10vh;
bottom: 0;
left: 0;
right: 0;
background-color: black;
opacity: 0.4;
height: 90vh;
width: 100%;
}
.cartbody{
background-color: white;
position: fixed;
height: 100vh;
width: 25vw;
top: 10%;
left: 75%;
z-index: 2100;
overflow-y: auto;
transform: translateX(100%);
transition: 0.7s ease;
box-shadow: rgba(0, 0, 0, 0.0) 0px 0px 0px, rgba(0, 0, 0, 0.30) 0px 3px 6px;
}
.carttotal{
font-size: 2rem;
color: rgb(22, 113, 119);
font-weight: bold;
margin-top: 1.5em;
text-align: center;
margin-bottom: 3em;
}
.cartbody i{
font-size: 2.2rem;
margin-left: 0.4em;
margin-top: 0.2em;
color: black;
font-weight: 200;
cursor: pointer;
transition: 0.3s ease;
}
.cartbody i:hover{
transform: scale(1.15);
}
.cartbody input{
width: 2.2rem;
height: auto;
}
.cartbodyactive{
transform: translateX(0%);
}
.carttitle{
text-align: center;
margin-top: 1em;
margin-bottom: 2em;
}
.cartitem{
display: flex;
justify-content: space-evenly;
}
.cartitem .itemtitle{
font-size: 1.2rem;
}
.cartitems{
display: flex;
flex-direction: column;
row-gap: 3em;
overflow-y: auto;
list-style: none;
padding-left: 0.5em;
}
.removebtn{
background-color: red;
color: black;
font-weight: bold;
outline: none;
border: none;
padding: 0.5em 1em;
cursor: pointer;
}
.p2{
height: 160vh;
position: relative;
}
.p2title{
color: black;
padding-top: 2.5em;
margin-left: 7%;
}
.p2 img{
height: 200px;
width: 300px;
}
.itemcontainer{
margin-top: 6em;
display: flex;
justify-content: space-around;
}
.itemcontainer2{
margin-top: 6em;
display: flex;
justify-content: space-around;
}
.item{
display: flex;
flex-direction: column;
align-items: center;
min-height: 355px;
justify-content: space-around;
}
.atcbtn{
background-color: white;
cursor: pointer;
text-decoration: none;
color: black;
width: 40%;
text-align: center;
font-weight: bold;
border: black solid 2px;
padding: 0.8em 0.5em;
transition: 0.4s ease;
}
.atcbtn:hover{
background-color: black;
color: white;
font-weight: bold;
}
爪哇腳本:
let TotalNumber = document.querySelector('.totalnumber');
const Atc = document.getElementsByClassName('atcbtn');
const cartbtn = document.getElementById('cartbtn')
const closeicon = document.getElementById('closeicon')
const cartbody = document.querySelector('.cartbody')
const removebtn = document.getElementsByClassName('removebtn')
const carttotal = document.querySelector('.carttotal')
let qinput = document.getElementsByClassName('qinput')
cartbtn.addEventListener('click', function(){
cartbody.classList.toggle('cartbodyactive')
})
closeicon.addEventListener('click', function(){
cartbody.classList.remove('cartbodyactive')
})
for(let i = 0; i < qinput.length; i++){
qinput[i].value= 1;
}
function removeitem(){
for (i = 0; i < removebtn.length; i++){
let rbutton = removebtn[i];
rbutton.addEventListener("click", function (){
let TotalNumbervalue = TotalNumber.innerHTML
if(TotalNumbervalue > 0){
TotalNumber.innerHTML--
console.log('if statement for negative works')
}
rbutton.parentElement.remove()
})
}
}
removeitem()
function additemtocart(){
for (i = 0; i < Atc.length; i++){
let button = Atc[i];
button.addEventListener("click", function (){
let TotalNumbervalue = TotalNumber.innerHTML
if(TotalNumbervalue > -1){
TotalNumber.innerHTML++
}
let shopitem = button.parentElement
let shoptitle = shopitem.getElementsByClassName('item-title')[0].innerText
let shopprice = shopitem.getElementsByClassName('itemprice')[0].innerText
let cartrow = document.createElement('div')
let cartitems = document.getElementsByClassName('cartitems')[0]
let cartrowcontent = `<li class="cartitem"><span class="itemtitle">${shoptitle}</span><span class="itemprice">${shopprice}</span><input type="number" id="qinput"><button class="removebtn">Remove</button></li>`
cartrow.innerHTML = cartrowcontent
cartitems.append(cartrow)
})
}
}
additemtocart()
您可以通過使用事件委托來顯着簡化您的邏輯(請參閱: 單擊事件)。 您將單個 eventListener 添加到文檔正文(或您要委托的按鈕/事件的任何共享祖先),並根據事件的目標觸發適當的回調。
function addItemToCart(item) {
console.log('add: ', item);
// ...
}
function removeItemFromCart(item) {
console.log('remove: ', item);
// ...
}
function handleDocumentClick(event) {
if (event.target.classList.contains('atcbtn')) {
addItemToCart(event.target.parentElement);
}
if (event.target.classList.contains('removebtn')) {
removeItemFromCart(event.target.parentElement);
}
}
document.body.addEventListener('click', handleDocumentClick);
使用這種簡單的方法,您不再需要知道購物車或商店中有多少商品/按鈕,它們都會觸發相關的回調。
您還會注意到,在上面我們將event.target.parentElement
傳遞給回調,這意味着我們可以直接使用該item
而無需在回調中進一步查詢。
您可能想要利用的下一個效率是data-attributes ,下面的代碼片段依賴於此。 我已經將每件商品的title
和price
作為數據屬性添加到父 div 中,這樣我們就可以訪問這些詳細信息,而無需查詢子元素的內容。
<div class="item" data-price="12.99" data-title="Shirt 2">
...
</div>
剩下的就是編寫從購物車中添加/刪除商品的邏輯,並更新標題中的相關購物車計數以及購物車中的購物車總數。
這里的代碼片段不處理購物車中數量的變化,但也許您可以看到如何使用委托來添加邏輯......
在此過程中編寫自己的購物車並處理驗證等工作很多,您可能想查看模板庫或購物車解決方案(想到 snipcart )。
const cartbody = document.querySelector('.cartbody'); const cartbtn = document.getElementById('cartbtn'); const closeicon = document.getElementById('closeicon'); cartbtn.addEventListener('click', function () { cartbody.classList.toggle('cartbodyactive'); }); closeicon.addEventListener('click', function () { cartbody.classList.remove('cartbodyactive'); }); const totalNumber = document.querySelector('.totalnumber'); const cartItemsUl = document.querySelector('.cartitems'); const cartTotal = document.querySelector('.carttotal'); function addItemToCart(item) { console.log('add: ', item); const { price, title } = item.dataset; const itemLi = document.createElement('li'); itemLi.className = 'cartitem'; itemLi.dataset.title = title; itemLi.dataset.price = price; itemLi.innerHTML = `<span class="itemtitle">${title}</span> <span class="itemprice">$${price}</span> <input type="number" class="qinput" id="qinput" value="1"> <button type="button" class="removebtn">Remove</button>`; cartItemsUl.appendChild(itemLi); // update item count totalNumber.textContent = +totalNumber.textContent + 1; // update cart total const updatedTotal = (parseFloat(cartTotal.dataset.total) + parseFloat(price)).toFixed(2); cartTotal.dataset.total = updatedTotal; cartTotal.textContent = `$${updatedTotal}`; } function removeItemFromCart(item) { console.log('remove: ', item); const { price, title } = item.dataset; item.remove() // update item count // will need to account for the quantity input value totalNumber.textContent = +totalNumber.textContent - 1; // update cart total const updatedTotal = (parseFloat(cartTotal.dataset.total) - parseFloat(price)).toFixed(2); cartTotal.dataset.total = updatedTotal; cartTotal.textContent = `$${updatedTotal}`; } function handleDocumentClick(event) { console.clear(); if (event.target.classList.contains('atcbtn')) addItemToCart(event.target.parentElement); if (event.target.classList.contains('removebtn')) removeItemFromCart(event.target.parentElement); } document.body.addEventListener('click', handleDocumentClick);
*{ padding: 0; margin: 0; box-sizing: border-box;}::-webkit-scrollbar{ display: none;}.wrapper{ overflow-x: hidden;}.topnavcont{ padding: 1em 0em; align-items: center; height: 10vh; width: 100vw; display: flex; justify-content: space-around; background-color: white; box-shadow: rgba(0, 0, 0, 0.10) 0px 3px 6px, rgba(0, 0, 0, 0.20) 0px 3px 6px; position: fixed; z-index: 5;}.topleftnav{ display: flex; justify-content: space-between; width: 10%; margin-left: -3%; font-weight: bold;}.topleftnav li{ cursor: pointer; list-style: none; font-size: 1.05rem; transition: 0.3s ease; border-bottom: transparent solid 2px;}.topleftnav li:hover{ border-bottom: black solid 2px; transform: scale(1.1);}.topnavtitle{ margin-right: 2.5%;}.navcartcontainer{ display: flex; margin-right: -1%; }.topnavcont .totalnumber{ color: black; padding: 0.2em 0.4em; border-radius: 50%; font-size: 1.25rem; height: fit-content; /* cursor: pointer; */ font-weight: bold;}.topnavcont i{ font-size: 2rem; margin-left: 0.3em; cursor: pointer; transition: 0.4s ease; }.topnavcont i:hover{ transform: scale(1.15);}.p1{ height: 100vh; position: relative;}.p1 img{ object-fit: cover; height: 100vh; width: 100%;}.p1 .overlay::after{ content: ""; position: absolute; top: 10vh; bottom: 0; left: 0; right: 0; background-color: black; opacity: 0.4; height: 90vh; width: 100%;}.cartbody{ background-color: white; position: fixed; height: 100vh; width: 25vw; top: 10%; left: 75%; z-index: 2100; overflow-y: auto; transform: translateX(100%); transition: 0.7s ease; box-shadow: rgba(0, 0, 0, 0.0) 0px 0px 0px, rgba(0, 0, 0, 0.30) 0px 3px 6px;}.carttotal{ font-size: 2rem; color: rgb(22, 113, 119); font-weight: bold; margin-top: 1.5em; text-align: center; margin-bottom: 3em;}.cartbody i{ font-size: 2.2rem; margin-left: 0.4em; margin-top: 0.2em; color: black; font-weight: 200; cursor: pointer; transition: 0.3s ease;}.cartbody i:hover{ transform: scale(1.15);}.cartbody input{ width: 2.2rem; height: auto;}.cartbodyactive{ transform: translateX(0%);}.carttitle{ text-align: center; margin-top: 1em; margin-bottom: 2em;}.cartitem{ display: flex; justify-content: space-evenly;}.cartitem .itemtitle{ font-size: 1.2rem;}.cartitems{ display: flex; flex-direction: column; row-gap: 3em; overflow-y: auto; list-style: none; padding-left: 0.5em;}.removebtn{ background-color: red; color: black; font-weight: bold; outline: none; border: none; padding: 0.5em 1em; cursor: pointer;}.p2{ height: 160vh; position: relative;}.p2title{ color: black; padding-top: 2.5em; margin-left: 7%;}.p2 img{ height: 200px; width: 300px;}.itemcontainer{ margin-top: 6em; display: flex; justify-content: space-around;}.itemcontainer2{ margin-top: 6em; display: flex; justify-content: space-around;}.item{ display: flex; flex-direction: column; align-items: center; min-height: 355px; justify-content: space-around;}.atcbtn{ background-color: white; cursor: pointer; text-decoration: none; color: black; width: 40%; text-align: center; font-weight: bold; border: black solid 2px; padding: 0.8em 0.5em; transition: 0.4s ease;}.atcbtn:hover{ background-color: black; color: white; font-weight: bold;}
<!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>E-Commerce Website</title> <link rel="stylesheet" href="/fonts/fontawesome-free-5.3.1-web/css/all.css"> <link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p" crossorigin="anonymous" /> <link rel="stylesheet" href="style.css"> <script src="app.js" async></script> </head> <body> <div class="wrapper"> <div class="p1"> <div class="topnavcont"> <ul class="topleftnav"> <li class="topnavlink">Home</li> <li class="topnavlink">Shop</li> </ul> <h1 class="topnavtitle">The Store</h1> <div class="navcartcontainer"> <h3 class="totalnumber">1</h3> <i class="fas fa-shopping-cart" id="cartbtn"></i> </div> </div> <img src="https://source.unsplash.com/random/200x200/?sig=0" alt="" class="bgimg"> <div class="overlay"></div> <div class="cartbody"> <i class="fal fa-times" id="closeicon"></i> <h2 class="carttitle">Shopping Cart</h2> <ul class="cartitems"> <li class="cartitem" data-title="Shirt 2" data-price="12.99"><span class="itemtitle">Shirt 2</span> <span class="itemprice">$12.99</span> <input type="number" class="qinput" id="qinput" value="1"> <button type="button" class="removebtn">Remove</button> </li> </ul> <div class="carttotal" data-total="12.99">Total: $12.99</div> </div> </div> <div class="p2"> <h1 class="p2title">My Shop</h1> <div class="itemcontainer"> <div class="item" data-price="8.99" data-title="Shirt 1"> <img src="https://source.unsplash.com/random/200x200/?sig=1" alt="" class="item-img"> <h1 class="item-title">Shirt 1</h1> <h3 class="itemprice">$8.99</h3> <!-- <a href="#" class="atcbtn">Add To Cart</a> --> <button type="button" class="atcbtn">Add To Cart</button> </div> <div class="item" data-price="12.99" data-title="Shirt 2"> <img src="https://source.unsplash.com/random/200x200/?sig=2" alt="" class="item-img"> <h1 class="item-title">Shirt 2</h1> <h3 class="itemprice" data-price="12.99">$12.99</h3> <!-- <a href="#" class="atcbtn">Add To Cart</a> --> <button type="button" class="atcbtn">Add To Cart</button> </div> <div class="item" data-price="3.99" data-title="Shirt 3"> <img src="https://source.unsplash.com/random/200x200/?sig=3" alt="" class="item-img"> <h1 class="item-title">Shirt 3</h1> <h3 class="itemprice" data-price="3.99">$3.99</h3> <!-- <a href="#" class="atcbtn">Add To Cart</a> --> <button type="button" class="atcbtn">Add To Cart</button> </div> </div> </div> </div> </body> </html>
原因是您在加載頁面后正在運行 removeitem()。 因此,它通過 document.getElementsByClassName('removebtn') 運行,並在我們第一次加載頁面時返回頁面上的刪除按鈕。
這就是為什么您可以刪除購物車中已經存在的項目,但不能刪除新項目的原因——這些新項目具有刪除按鈕,這些按鈕不是由for... in循環迭代的。
您可以通過簡單地在 Atc 的 eventListener 內的回調函數底部添加 removeitem() 來解決這個問題,因此每次向購物車添加新項目時,removeitem 將再次運行並遍歷頁面中的每個刪除按鈕,包括新的。 希望這是有道理的!
它看起來像這樣:
function additemtocart() {
for (i = 0; i < Atc.length; i++) {
let button = Atc[i];
button.addEventListener("click", function () {
let TotalNumbervalue = TotalNumber.innerHTML
if (TotalNumbervalue > -1) {
TotalNumber.innerHTML++
}
let shopitem = button.parentElement
let shoptitle = shopitem.getElementsByClassName('item-title')[0].innerText
let shopprice = shopitem.getElementsByClassName('itemprice')[0].innerText
let cartrow = document.createElement('div')
let cartitems = document.getElementsByClassName('cartitems')[0]
let cartrowcontent = `<li class="cartitem"><span class="itemtitle">${shoptitle}</span><span class="itemprice">${shopprice}</span><input type="number" id="qinput"><button class="removebtn">Remove</button></li>`
cartrow.innerHTML = cartrowcontent
cartitems.append(cartrow)
removeitem();
})
}
}
additemtocart()
編輯
我怎么能用 '''''for(let i = 0; i < qinput.length; i++){ qinput[i].value= 1; }''''' 我也將它添加到函數的底部,但輸入值未更新
所以,當你在 Atc 的 eventListener 中定義carrowcontent時,你沒有設置 qinput 類,只是 id =>
let cartrowcontent = `<li class="cartitem"><span class="itemtitle">${shoptitle}</span><span class="itemprice">${shopprice}</span><input type="number" id="qinput"><button class="removebtn">Remove</button></li>`
我做了什么:
在函數中涉及 qinput 循環:
function updateQInput() {
for (let i = 0; i < qinput.length; i++) {
qinput[i].value = 1;
}
}
updateQInput();
並在 Atc 的 eventListener 底部調用它(添加類“qinput”后):
button.addEventListener("click", function () {
let TotalNumbervalue = TotalNumber.innerHTML
if (TotalNumbervalue > -1) {
TotalNumber.innerHTML++
}
let shopitem = button.parentElement
let shoptitle = shopitem.getElementsByClassName('item-title')[0].innerText
let shopprice = shopitem.getElementsByClassName('itemprice')[0].innerText
let cartrow = document.createElement('div')
let cartitems = document.getElementsByClassName('cartitems')[0]
let cartrowcontent = `<li class="cartitem"><span class="itemtitle">${shoptitle}</span><span class="itemprice">${shopprice}</span><input type="number" class="qinput" id="qinput"><button class="removebtn">Remove</button></li>`
cartrow.innerHTML = cartrowcontent
cartitems.append(cartrow)
removeitem();
updateQInput();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.