防止点击事件将重复项添加到数组,Vanilla JS
Prevent click event from adding duplicate items to an array, Vanilla JS
我有一套 4 件物品和一个按钮。单击一个项目应该将该项目添加到一个空数组中。然后点击按钮会显示选中的项目数。
我已经遍历了 HTML 集合,并使用 push 方法在单击每个项目时添加它们。但是,每次额外的点击都会将原始项目的副本添加到数组中。因此,数组长度总计为 4,而不是总长度为 10。
这是控制台每次点击的示例:
["item 2"]
["item 2", "item 2", "item 3"]
["item 2", "item 2", "item 3", "item 2", "item 3", "item 4"]
["item 2", "item 2", "item 3", "item 2", "item 3", "item 4", "item 1", "item 2", "item 3", "item 4"]
我认为这个问题与事件冒泡有关,但我不确定如何进行。
这是 FIDDLE。
const noticeMod = document.getElementById('notice');
const noticeInner = document.getElementById('message');
const windowOverlay = document.getElementById('overlay');
let itemsSelected = [];
function appendMessage() {
let elSpan = document.createElement('span');
elSpan.textContent = `You Downloaded ${itemsSelected.length} items.`;
noticeInner.appendChild(elSpan);
}
function removeMessage() {
let emptySpan = document.querySelectorAll('#message span');
emptySpan[0].remove();
}
function openNotification() {
noticeMod.classList.add('show-notice');
windowOverlay.classList.add('show-overlay');
}
function closeNotification() {
noticeMod.classList.remove('show-notice');
windowOverlay.classList.remove('show-overlay');
}
function addItems() {
const currentItem = document.getElementsByClassName('item');
for (i = 0; i < currentItem.length; i++) {
let itemName = document.querySelectorAll('.item-title')[i].textContent;
if (currentItem[i].classList.contains('item-selected')) {
itemsSelected.push(itemName);
}
}
console.log(itemsSelected);
}
//addItems();
document.addEventListener('click', function(event) {
if (event.target.matches('#submitBtn')) {
appendMessage();
openNotification();
}
if (event.target.matches('#closeBtn') || event.target.matches('#overlay')) {
removeMessage();
closeNotification();
}
if (event.target.matches('.item-selected')) {
event.target.classList.remove('item-selected');
} else if (event.target.matches('.item')) {
event.target.classList.add('item-selected');
addItems();
}
}, false);
body {
background: #191919;
color: #fff;
position: relative;
}
.notice-modal {
background: #242424;
border: 1px solid #555;
position: fixed;
right: 0;
top: 12px;
transform: translateX(100%);
transition: 500ms ease;
z-index: 1000;
}
.show-notice {
right: 12px;
transform: translateX(0%);
transition: 500ms ease;
}
.close span {
cursor: pointer;
border-left: 2px solid #555;
padding-left: 12px;
margin-left: 12px;
}
.transparent-overlay {
position: fixed;
display: none;
top: 0;
left: 0;
right: 0;
bottom: 0;
cursor: pointer;
background-color: #191919;
opacity: 0;
z-index: 990;
}
.show-overlay {
display: block;
}
.row {
display: flex;
flex-direction: row;
justify-content: space-between;
flex-wrap: wrap;
padding: 12px;
}
.item {
cursor: pointer;
background: #242424;
padding: 20px;
border: 3px solid #242424;
margin-bottom: 12px;
}
.item-selected {
border: 3px solid #2269a8;
}
.item-title {
font-size: 18px;
}
.cta {
margin: 0 auto;
padding: 12px;
}
#submitBtn {
cursor: pointer;
border: none;
background: #2269a8;
padding: 12px;
color: #fff;
width: 100%;
}
#submitBtn:hover {
background: #235596;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.3/js/bootstrap.min.js"></script>
<aside id="notice" class="notice-modal">
<div class="row">
<div id="message"></div>
<div class="close">
<span id="closeBtn">✕</span>
</div>
</div>
</aside>
<div id="overlay" class="transparent-overlay"></div>
<section class="row">
<div class="item">
<h1 class="item-title">item 1</h1>
</div>
<div class="item">
<h1 class="item-title">item 2</h1>
</div>
<div class="item">
<h1 class="item-title">item 3</h1>
</div>
<div class="item">
<h1 class="item-title">item 4</h1>
</div>
</section>
<section class="cta">
<button id="submitBtn">Submit</button>
</section>
问题出在您的 addItems
方法上。你如何识别当前点击的项目?每次调用 addItems 方法时,它都会找到名称为 class item-selected
的所有项目。所以第一次点击只有一个项目被选中。但每次点击后,您将获得所有先前点击的项目。现在有两种方法,
如果您确定项目名称是唯一的,那么您可以在 addItems 方法中检查重复项目并仅添加新项目。
function addItems() {
const currentItem = document.getElementsByClassName('item');
for(i = 0; i < currentItem.length; i++) {
let itemName = document.querySelectorAll('.item-title')[i].textContent;
if (currentItem[i].classList.contains('item-selected') && itemsSelected.indexOf(itemName) === -1) {
itemsSelected.push(itemName);
}
}
console.log(itemsSelected);
}
如果您不确定名称是否唯一,那么您可以将当前单击的元素传递给 addItems 方法。
function addItems(currentElement) {
let itemName = currentElement.innerText;
if (itemsSelected.indexOf(itemName) === -1) {
itemsSelected.push(itemName);
}
console.log(itemsSelected);
}
并像这样调用 addItems 方法,
addItems(event.target);
希望这个例子对你有所帮助。
在示例中,值在第一次点击时添加,在第二次点击时删除。
let array = []
document.querySelector('.container').addEventListener('click', (e) => {
if (e.target.classList.contains('item')) {
e.target.classList.toggle('active')
const index = array.indexOf(e.target.textContent)
if (index !== -1) {
array = array.filter((e, i) => i !== index)
} else {
array.push(e.target.textContent)
}
console.log(array)
}
})
.item {
background-color: lightgreen;
width: 100px;
height: 100px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border: 2px dotted green;
}
.item:hover {
cursor: pointer;
}
.item.active {
border-style: solid;
}
.container {
width: 70%;
margin: 0 auto;
display: flex;
justify-content: space-between;
}
<div class="container">
<div class="item">item 1</div>
<div class="item">item 2</div>
<div class="item">item 3</div>
<div class="item">item 4</div>
</div>
我有一套 4 件物品和一个按钮。单击一个项目应该将该项目添加到一个空数组中。然后点击按钮会显示选中的项目数。
我已经遍历了 HTML 集合,并使用 push 方法在单击每个项目时添加它们。但是,每次额外的点击都会将原始项目的副本添加到数组中。因此,数组长度总计为 4,而不是总长度为 10。
这是控制台每次点击的示例:
["item 2"]
["item 2", "item 2", "item 3"]
["item 2", "item 2", "item 3", "item 2", "item 3", "item 4"]
["item 2", "item 2", "item 3", "item 2", "item 3", "item 4", "item 1", "item 2", "item 3", "item 4"]
我认为这个问题与事件冒泡有关,但我不确定如何进行。
这是 FIDDLE。
const noticeMod = document.getElementById('notice');
const noticeInner = document.getElementById('message');
const windowOverlay = document.getElementById('overlay');
let itemsSelected = [];
function appendMessage() {
let elSpan = document.createElement('span');
elSpan.textContent = `You Downloaded ${itemsSelected.length} items.`;
noticeInner.appendChild(elSpan);
}
function removeMessage() {
let emptySpan = document.querySelectorAll('#message span');
emptySpan[0].remove();
}
function openNotification() {
noticeMod.classList.add('show-notice');
windowOverlay.classList.add('show-overlay');
}
function closeNotification() {
noticeMod.classList.remove('show-notice');
windowOverlay.classList.remove('show-overlay');
}
function addItems() {
const currentItem = document.getElementsByClassName('item');
for (i = 0; i < currentItem.length; i++) {
let itemName = document.querySelectorAll('.item-title')[i].textContent;
if (currentItem[i].classList.contains('item-selected')) {
itemsSelected.push(itemName);
}
}
console.log(itemsSelected);
}
//addItems();
document.addEventListener('click', function(event) {
if (event.target.matches('#submitBtn')) {
appendMessage();
openNotification();
}
if (event.target.matches('#closeBtn') || event.target.matches('#overlay')) {
removeMessage();
closeNotification();
}
if (event.target.matches('.item-selected')) {
event.target.classList.remove('item-selected');
} else if (event.target.matches('.item')) {
event.target.classList.add('item-selected');
addItems();
}
}, false);
body {
background: #191919;
color: #fff;
position: relative;
}
.notice-modal {
background: #242424;
border: 1px solid #555;
position: fixed;
right: 0;
top: 12px;
transform: translateX(100%);
transition: 500ms ease;
z-index: 1000;
}
.show-notice {
right: 12px;
transform: translateX(0%);
transition: 500ms ease;
}
.close span {
cursor: pointer;
border-left: 2px solid #555;
padding-left: 12px;
margin-left: 12px;
}
.transparent-overlay {
position: fixed;
display: none;
top: 0;
left: 0;
right: 0;
bottom: 0;
cursor: pointer;
background-color: #191919;
opacity: 0;
z-index: 990;
}
.show-overlay {
display: block;
}
.row {
display: flex;
flex-direction: row;
justify-content: space-between;
flex-wrap: wrap;
padding: 12px;
}
.item {
cursor: pointer;
background: #242424;
padding: 20px;
border: 3px solid #242424;
margin-bottom: 12px;
}
.item-selected {
border: 3px solid #2269a8;
}
.item-title {
font-size: 18px;
}
.cta {
margin: 0 auto;
padding: 12px;
}
#submitBtn {
cursor: pointer;
border: none;
background: #2269a8;
padding: 12px;
color: #fff;
width: 100%;
}
#submitBtn:hover {
background: #235596;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.3/js/bootstrap.min.js"></script>
<aside id="notice" class="notice-modal">
<div class="row">
<div id="message"></div>
<div class="close">
<span id="closeBtn">✕</span>
</div>
</div>
</aside>
<div id="overlay" class="transparent-overlay"></div>
<section class="row">
<div class="item">
<h1 class="item-title">item 1</h1>
</div>
<div class="item">
<h1 class="item-title">item 2</h1>
</div>
<div class="item">
<h1 class="item-title">item 3</h1>
</div>
<div class="item">
<h1 class="item-title">item 4</h1>
</div>
</section>
<section class="cta">
<button id="submitBtn">Submit</button>
</section>
问题出在您的 addItems
方法上。你如何识别当前点击的项目?每次调用 addItems 方法时,它都会找到名称为 class item-selected
的所有项目。所以第一次点击只有一个项目被选中。但每次点击后,您将获得所有先前点击的项目。现在有两种方法,
如果您确定项目名称是唯一的,那么您可以在 addItems 方法中检查重复项目并仅添加新项目。
function addItems() {
const currentItem = document.getElementsByClassName('item');
for(i = 0; i < currentItem.length; i++) {
let itemName = document.querySelectorAll('.item-title')[i].textContent;
if (currentItem[i].classList.contains('item-selected') && itemsSelected.indexOf(itemName) === -1) {
itemsSelected.push(itemName);
}
}
console.log(itemsSelected);
}
如果您不确定名称是否唯一,那么您可以将当前单击的元素传递给 addItems 方法。
function addItems(currentElement) { let itemName = currentElement.innerText; if (itemsSelected.indexOf(itemName) === -1) { itemsSelected.push(itemName); } console.log(itemsSelected); }
并像这样调用 addItems 方法,
addItems(event.target);
希望这个例子对你有所帮助。 在示例中,值在第一次点击时添加,在第二次点击时删除。
let array = []
document.querySelector('.container').addEventListener('click', (e) => {
if (e.target.classList.contains('item')) {
e.target.classList.toggle('active')
const index = array.indexOf(e.target.textContent)
if (index !== -1) {
array = array.filter((e, i) => i !== index)
} else {
array.push(e.target.textContent)
}
console.log(array)
}
})
.item {
background-color: lightgreen;
width: 100px;
height: 100px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border: 2px dotted green;
}
.item:hover {
cursor: pointer;
}
.item.active {
border-style: solid;
}
.container {
width: 70%;
margin: 0 auto;
display: flex;
justify-content: space-between;
}
<div class="container">
<div class="item">item 1</div>
<div class="item">item 2</div>
<div class="item">item 3</div>
<div class="item">item 4</div>
</div>