Счетчик при помощи замыкания и события event
Не могу понять как работает пример из интернета. На странице несколько div-ов с текстом (пусть будет 3). Хочу, чтобы при клике на каждый из них отображалось количество кликов по каждому. На каждый div вешать обработчик не собираюсь. В скрипте уже есть счетчик кликов. Не могу понять как нужно передать значение event.target в счетчик.
const widjet = document.getElementsByClassName('widjet')[0]
const wrapper = document.querySelector('.widjet__wrapper');
function test(elem) {
let num = 1;
return function() {
num++;
elem.textContent = String(num);
}
}
wrapper.addEventListener('click', (event) => {
let target = event.target;
test(target);
})
<div class="widjet__wrapper">
<div class="widjet">0</div>
<div class="widjet">0</div>
<div class="widjet">0</div>
</div>
- Отдельно, счетчик на замыкании работает
- Отдельно, работает event.target
У меня никак не получается их подружить.
Надо, чтобы работало вместе и чтобы при клике на каждый html-элемент, в его тексте был его счетчик.
Ответы (3 шт):
Сохраняя общую логику автора кода, можно присвоить некому свойству test
для каждого target
при нажатии возвращаемую анонимную функцию из функции test
, в замыкании которой мы имеем доступ как к num
, так и к elem
. Тут же вызываем эту функцию, привязанную к конкретному элементу. Далее по нажатии только вызываем ее.
const widjet = document.getElementsByClassName('widjet')[0]
const wrapper = document.querySelector('.widjet__wrapper');
function test(elem) {
let num = 0;
return function() {
num++;
elem.textContent = String(num);
}
}
wrapper.addEventListener('click', (event) => {
let target = event.target;
if (!target.test) {
target.test = test(target);
}
target.test();
})
<div class="widjet__wrapper">
<div class="widjet">0</div>
<div class="widjet">0</div>
<div class="widjet">0</div>
</div>
Самое разумное, это вешать на каждый div свой собственный обработчик событий:
const wrapper = document.querySelectorAll('.widjet');
function test(elem) {
let num = 0;
return () => elem.textContent = String(++num);
}
wrapper.forEach(el => {
el.addEventListener('click', test(el));
})
<div class="widjet__wrapper">
<div class="widjet">0</div>
<div class="widjet">0</div>
<div class="widjet">0</div>
</div>
Без этого, придется придумывать костыли, где и как хранить значения.
Если значения сохранять в свойстве html элемента или во внешней переменной, то это уже не замыкание получается.
На каждый div вешать обработчик не собираюсь.
Если так - значит нужно:
- изменить счетчик
- в обработчике работать с "target" события
Предложу вот такой вариант...
const wrapper = document.querySelector('.widjet__wrapper');
function test() {
const num = new Map();
return function(e) {
const o = e.target.closest('.widjet')
if (!o) return
const v = num.has(o) ? num.get(o) + 1 : 1;
num.set(o, v)
o.textContent = v;
}
}
wrapper.addEventListener('click', test())
<div class="widjet__wrapper">
<div class="widjet">0</div>
<div class="widjet">0</div>
<div class="widjet">0</div>
</div>