Делегирование событий! Как добраться до элементов ниже? (Подобие слайдера на странице)

378
11 октября 2021, 09:00

Есть некоторая структура :

<div class="team-workers"> // некий врапер
  <div class="team-workers-card"> // шаблон самого дублируемого элемента
    <div class="team-workers-card__photo"> // цель
    </div>
    <div class="team-workers-card__name"> // цель 
    </div>
    <div class="team-workers-card__socials"> // цель
    </div>
    <div class="team-workers-card__description"> // цель
    </div>
  </div>
</div>

И таких элементов "team-workers-card" допустим несколько.

Каким образом через делегирование событий мне добраться до элементов которые ниже чем "team-workers-card" ? addEventListener вешается только на элементы которые добавлены всё таки обычным querySelector.

let cardIndex = 1,
    cardList = document.querySelector('.team-workers'),
    cards = document.querySelectorAll('.team-workers-card'),
cardList.addEventListener('click',function (event) {
        for (let i = 0; i < cards.length + 1; i++) {
            if (event.target.matches('.team-workers-card') 
                && event.target == cards[i-1]){
                ***
            }
        }
});

Контекст всего этого неважен, но суть в том, что я бы был доволен результатом если бы только не одно но, контент этих блоков замещает всё пространство родительского .team-workers-card и я могу достучаться до него только нажав на паддинги по бокам от этого блока

=== Контекст ===

Но для контекста всё же опишу задачу. Мало ли, может есть другие решения. Смысл в том, чтобы кликая на эти карточки людей - это срабатывало точно так же как и с точками внизу. Навигацию по точкам я реализовал этим же методом, делегированием событий. То есть посадил addEventListener на обёртку и проверял нажал ли я на нужный элемент, но вот с этими карточками я столкнулся с проблемой , которую уже описал выше. Элементы посаженные в обёртку полностью занимают пространство и невозможно кликнуть по самой карточке, а достучаться до элементов ниже - понятия не имею как.

Answer 1

Вам нужен элемент.closest(селектор) — начиная от данного элемента - ищет среди его родителей подходящий элемент. Если найдет - вернет первый найденный. Иначе - null. Т.е. если в коде ниже target будет null - условие не выполнится.

let wrapper = document.querySelector('.team-workers'); 
let cards = document.querySelectorAll('.team-workers-card'); 
let bullets = document.querySelectorAll('.bullet'); 
let cardList = Array.from(cards); 
let lastClickedIndex = 0; 
 
wrapper.addEventListener('click', function(e) { 
  let target = e.target.closest('.team-workers-card'); 
  if ( target ) { 
    let index = cardList.indexOf( target ); 
    console.clear(); 
    console.log( "Кликнут номер: " + index ); 
     
    cards[ lastClickedIndex ].classList.remove('active'); 
    bullets[ lastClickedIndex ].classList.remove('active'); 
     
    bullets[index].classList.add('active'); 
    target.classList.add('active'); 
 
    lastClickedIndex = index; 
  } 
});
[class^="team-workers-card__"] { 
  width: 100px; 
  height: 40px; 
  background-color: orange; 
  margin: 2px; 
} 
 
.team-workers-card { 
  display: inline-block; 
  border: 2px solid #123; 
  padding: 3px; 
  margin: 5px; 
} 
 
.bullet { 
  width: 20px; 
  height: 20px; 
  border-radius: 50%; 
  display: inline-block; 
  background-color: orange; 
} 
 
.bullet.active { 
  background-color: red; 
} 
.team-workers-card.active { 
  border-color: red; 
}
<div class="bullet"></div> 
<div class="bullet"></div> 
<div class="bullet"></div> 
<div class="bullet"></div> 
 
<div class="team-workers"> 
  <div class="team-workers-card"> 
    <div class="team-workers-card__photo"></div> 
    <div class="team-workers-card__name"></div> 
    <div class="team-workers-card__socials"></div> 
    <div class="team-workers-card__description"></div> 
  </div> 
  <div class="team-workers-card"> 
    <div class="team-workers-card__photo"></div> 
    <div class="team-workers-card__name"></div> 
    <div class="team-workers-card__socials"></div> 
    <div class="team-workers-card__description"></div> 
  </div> 
  <div class="team-workers-card"> 
    <div class="team-workers-card__photo"></div> 
    <div class="team-workers-card__name"></div> 
    <div class="team-workers-card__socials"></div> 
    <div class="team-workers-card__description"></div> 
  </div> 
  <div class="team-workers-card"> 
    <div class="team-workers-card__photo"></div> 
    <div class="team-workers-card__name"></div> 
    <div class="team-workers-card__socials"></div> 
    <div class="team-workers-card__description"></div> 
  </div> 
</div>

Мало ли, может есть другие решения.

Да... Например не заморачиваться с делегированием, потому что сказали, что так работает быстрее) Когда у вас всего 4 элемента (даже 1000), разница не ощутима. Вот если будет 100 000 элементов, делегирование и правда помогает сэкономить примерно 1 секунду на загрузку. Но когда уже догрузилось - при клике нет разницы в скорости срабатывания.

Поэтому (вкусовщина) в большинстве случаев предпочитаю перебор, т.к. сразу можно получить индекс кликнутого элемента:

let wrapper = document.querySelector('.team-workers'); 
let cards = document.querySelectorAll('.team-workers-card'); 
let bullets = document.querySelectorAll('.bullet'); 
let lastClickedIndex = 0; 
 
Array.from(cards).forEach(function(elem, index){ 
  elem.addEventListener('click', function(){ 
    console.clear(); console.log(index); 
     
    cards[ lastClickedIndex ].classList.remove('active'); 
    bullets[ lastClickedIndex ].classList.remove('active'); 
     
    bullets[index].classList.add('active'); 
    this.classList.add('active'); 
     
    lastClickedIndex = index; 
  }); 
});
[class^="team-workers-card__"] { 
  width: 100px; 
  height: 40px; 
  background-color: orange; 
  margin: 2px; 
} 
 
.team-workers-card { 
  display: inline-block; 
  border: 2px solid #123; 
  padding: 3px; 
  margin: 5px; 
} 
 
.bullet { 
  width: 20px; 
  height: 20px; 
  border-radius: 50%; 
  display: inline-block; 
  background-color: orange; 
} 
 
.bullet.active { 
  background-color: red; 
} 
.team-workers-card.active { 
  border-color: red; 
}
<div class="bullet"></div> 
<div class="bullet"></div> 
<div class="bullet"></div> 
<div class="bullet"></div> 
 
<div class="team-workers"> 
  <div class="team-workers-card"> 
    <div class="team-workers-card__photo"></div> 
    <div class="team-workers-card__name"></div> 
    <div class="team-workers-card__socials"></div> 
    <div class="team-workers-card__description"></div> 
  </div> 
  <div class="team-workers-card"> 
    <div class="team-workers-card__photo"></div> 
    <div class="team-workers-card__name"></div> 
    <div class="team-workers-card__socials"></div> 
    <div class="team-workers-card__description"></div> 
  </div> 
  <div class="team-workers-card"> 
    <div class="team-workers-card__photo"></div> 
    <div class="team-workers-card__name"></div> 
    <div class="team-workers-card__socials"></div> 
    <div class="team-workers-card__description"></div> 
  </div> 
  <div class="team-workers-card"> 
    <div class="team-workers-card__photo"></div> 
    <div class="team-workers-card__name"></div> 
    <div class="team-workers-card__socials"></div> 
    <div class="team-workers-card__description"></div> 
  </div> 
</div>

Смотрите сами, как вам удобнее)

READ ALSO
Как разделить число на разряды?

Как разделить число на разряды?

Как сделать чтобы число делилось на разряды для цен?

201
Вывести ответ в массиве

Вывести ответ в массиве

пример немного изменил так как я массив получаю var weight = documentquerySelectorAll('

107