防止点击事件将重复项添加到数组,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">&#10005;</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);

}
  1. 如果您不确定名称是否唯一,那么您可以将当前单击的元素传递给 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>