Счетчик кликов для разных кнопок с помощью замыканий JS
Задание звучит так: Даны кнопки. Привяжите к каждой кнопке событие по клику, которое будет считать количество нажатий по кнопке и выводить его в текст кнопки. Количество нажатий для каждой кнопки должно хранится в замыкании.
У меня получилось создать только счетчик, который считает клики по всем кнопкам, но не по отдельности (если я кликнул на кнопку1 3 раза, то кликнув на кнопку2 вместо 1 я получу 4 а после клика на кнопку3 я получу 5). Если я пытаюсь отдельно для каждой кнопки описать счетчик, то получаю ошибку res is not a function:
btn1.addEventListener('click', function(){
function func (){
let k = 0;
function count(){
return k++
}
return count()
}
let res = func();
btn1.innerText = res()
})
Можно ли как-то разделить счетчик, чтобы он считал клики для каждой кнопки отдельно начиная с 0?
Вот мой код, в котором счетчик работает для всех кнопок вместе:
btn1 = document.getElementById('1')
btn2 = document.getElementById('2')
btn3 = document.getElementById('3')
function func() {
let k = 0;
return function count() {
return k++
}
}
let res = func ()
btn1.onclick = () => {
btn1.innerText = res()
}
btn2.onclick = () => {
btn2.innerText = res()
}
btn3.onclick = () => {
btn3.innerText = res()
}
Ответы (3 шт):
Попробуйте как-то вот так
const clickBtns = document.querySelectorAll('.clicker');
for (let elem of clickBtns) {
elem.addEventListener('click', (e) => {
if (!isNaN(parseInt(e.target.innerHTML))) {
e.target.innerHTML = parseInt(e.target.innerHTML) + 1;
} else {
e.target.innerHTML = 1;
}
})
}
<button class='clicker'>Кнопка</button>
<button class='clicker'>Кнопка</button>
<button class='clicker'>Кнопка</button>
Вот типичный счетчик с использованием замыканий. Ваша ошибка была только в том, что вы не создавали отдельный счетчик для каждой кнопки, а использовали один для всех - res.
const buttons = document.querySelectorAll('button'); // получаем NodeList с кнопками
/**
* Функция счетчика
*/
function count() {
let counter = 0;
return function() {
return counter+=1;
};
}
for (let button of buttons) {
const counter = count(); // создаем отдельный инстанс функции счетчика для каждой кнопки
button.addEventListener('click', function() {
this.textContent = counter(); // прибавляем +1 к счетчику внутри counter
});
}
<button>0</button>
<button>0</button>
<button>0</button>
Вряд ли ждут такого ответа, но формально это тоже замыкание:
for (let btn of document.querySelectorAll("button")) {
let clicks = 0
btn.addEventListener('click', e => {
btn.textContent = ++clicks
})
}
button { min-width: 7ch }
<button>0</button>
<button>0</button>
<button>0</button>
<button>0</button>
<button>0</button>
А ожидают увидеть скорее всего что-то такое:
function makeClickHandler() {
var clicks = 0
return e => e.target.textContent = ++clicks
}
for (let btn of document.querySelectorAll("button")) {
btn.addEventListener('click', makeClickHandler())
}
button { min-width: 7ch }
<button>0</button>
<button>0</button>
<button>0</button>
<button>0</button>
<button>0</button>
Есть ещё один вариант, который тоже использует замыкание, но почти наверняка его забракуют как и первый:
function main() {
var clicks = new Map()
document.addEventListener('click', e => {
var btn = e.target.closest('button')
if (btn) {
var count = (clicks.get(btn) ?? 0) + 1
clicks.set(btn, count)
btn.textContent = count
}
})
}
main()
button { min-width: 7ch }
<button>0</button>
<button>0</button>
<button>0</button>
<button>0</button>
<button>0</button>
Ну и в качестве бонуса, как бы я сделал такой счётчик без требования на использование замыкания:
document.addEventListener('click', e => {
var btn = e.target.closest('button')
if (btn) ++btn.textContent
})
button { min-width: 7ch }
<button>0</button>
<button>0</button>
<button>0</button>
<button>0</button>
<button>0</button>