#javascript
Вопрос:
У меня есть три кнопки. Все, что мне нужно, это добавить в массив соответствующее значение, нажав на кнопку, но если значение уже существует в моем массиве, мне нужно удалить его из моего массива. Мой код работает только в том случае, если мы используем его дважды (добавляем и удаляем) одну и ту же кнопку. Но если мы используем его с другими — он ломается. Попробуйте это на примере ниже. В чем причина такого поведения ?
Только чистый JavaScript.
let buttons = document.querySelectorAll('.string')
let array = []
let value = ''
buttons.forEach(el => el.addEventListener('click', () => {
value = el.innerHTML
for (i = 0; array.length 1; i ) {
if (array[i] === value) {
delete array[i]
array = array.filter(x => x) // clear empty values
console.log('deleted', array)
} else {
array.push(value)
console.log('added', array)
}
break
}
}))
<div class="block">
<div class="string">some</div>
<div class="string">else</div>
<div class="string">other</div>
</div>
Ответ №1:
Это работает не так, как вы ожидаете, потому что, если значение не совпадает с первым элементом массива, оно выталкивается и цикл прерывается. (Ваш цикл всегда прерывается после первого индекса в любом случае…)
Вместо этого вы можете просто использовать Array.prototype.indexOf
, чтобы получить индекс элемента, если он существует в массиве, а затем удалить этот индекс, если он существует, или нажать на него, если его нет.
Вы также можете использовать Array.prototype.splice(index, deleteCount)
для удаления ненужного индекса вместо выполнения delete
и Array.prototype.filter
.
let buttons = document.querySelectorAll('.string')
let array = []
let value = ''
buttons.forEach(el => el.addEventListener('click', () => {
value = el.innerHTML
let i = array.indexOf(value);
if(i > -1)
{
array.splice(i, 1);
console.log('deleted', array)
}
else
{
array.push(value)
console.log('added', array)
}
}))
<div class="block">
<div class="string">some</div>
<div class="string">else</div>
<div class="string">other</div>
</div>
Если бы вы хотели использовать вместо этого цикл for, я также исправил ваш исходный фрагмент, чтобы он работал с использованием цикла, который у вас был:
let buttons = document.querySelectorAll('.string')
let array = []
let value = ''
buttons.forEach(el => el.addEventListener('click', () => {
value = el.innerHTML
if(array.length < 1)
{
array.push(value)
console.log("added", array)
return
}
for (i = 0; i < array.length; i ) {
if (array[i] === value) {
array.splice(i, 1)
console.log('deleted', array)
break
} else if (i == array.length - 1) {
array.push(value)
console.log('added', array)
break
}
}
}))
<div class="block">
<div class="string">some</div>
<div class="string">else</div>
<div class="string">other</div>
</div>
Ответ №2:
1) Вы можете сделать его более эффективным, если используете Set здесь, потому что доступ к значению намного лучше, чем доступ к значению из массива.
2) Лучше использовать textContent
вместо innerHTML
.
let buttons = document.querySelectorAll('.string')
let array = [];
const set = new Set();
buttons.forEach(el => el.addEventListener('click', () => {
const text = el.textContent;
if (!set.has(text)) {
set.add(text);
array.push(text);
} else {
const index = array.indexOf(text);
array.splice(index, 1);
set.delete(text);
}
console.log(array);
}))
<div class="block">
<div class="string">some</div>
<div class="string">else</div>
<div class="string">other</div>
</div>