Строптивый и не отзывчивый
Есть список в нем его детишки-liшки:
ul {
padding: 30px;
border: 1px solid #8f93b6;
}
li {
list-style-type: none;
margin-bottom: 20px;
border: 1px dashed black;
}
<ul id="elem">
<li id="li">text</li>
<li>text</li>
<li>text</li>
<li>text</li>
<li>text</li>
</ul>
И вот я задумал обратится к <li> и по клику именно на него добавлять вопросительный знак в конец его текста, а в случае клика на <ul> добавить новый элемент <li> снизу. Не сработало, хотя я писал самые вежливы обращения:
let ul = document.querySelector('#elem')
//Ниже варианты обращения к li
let li = ul.firstElementChild.cloneNode(true)
let liID = document.getElementById('li')
let liAll = document.querySelectorAll('li')
// let liTag = document.getElementsByTagName('li') // HTMLcollection тоже самое что и liAll
// let liCh = ul.children // HTMLcollection тоже самое что и liAll
ul.addEventListener('click', foo)
function foo(ev) {
console.log(ev.target) // <li>
console.log("Put all <li> together version: ", ev.target === liAll ); // false при обращении к HTMLcollection
console.log("Personal index version: ", ev.target === liAll[0]); // true только если кликнуть на указанный индекс
console.log("Personal <li id='li'> version: ", ev.target === liID); // true только если кликнуть на указанный ID
if (ev.target === li) { // Тут было вместо li - 'li', liAll, liID, liAll[0], 'LI'
ev.target.innerHTML += '?'
}
this.append(li)
}
Выходит, чтобы добраться до <li> мне нужно каждому придать id и привязать событие к нему, что абсурд. Или перебрать циклом HTMLcollection(не важно каким способом добытую) и связать элементы цикла с событием ev, что тоже кажется не изящным.
Одно интересное, что в ev.target есть свойства nodeName: "LI"; и localName: "li". А значит ev.target.localName === 'li'; или ev.target.nodeName === 'LI'; вернет true и наша задумка заработает, но нет тут уникальности, что если на странице много и других li под другими ul, а мне нужны именно эти li.
Вопрос как добраться до всех <li> без цикла, без id, и фамильярных обращений в стиле ev.target.localName?
Второе почему у меня добавляется в конец <ul> всего один элемент <li>? Потом событие будто отвязывается. Хотелось бы множить их нажатиями.
Ответы (3 шт):
Скорее всего кроме как через цикл или получение свойств события не получится никак.
Вы, на самом деле почти добились поставленной цели, только вам нужно сравнивать не ev.target с li, а ev.target.nodeName с 'li', и тогда ? будет добавляться к нажатому элементу. Поскольку событие вы навесили на родительский ul, другие ul и li затронуты никак не будут (кроме вложенных, это исправляется доп проверкой ev.target.parentElement == ul).
Почему добавляется только один элемент? Потому что вы пытаетесь добавить один и тот же элемент много раз (это как дважды на елку повесить один и тот же шарик). Вам необходимо создавать или клонировать элемент, а потом уже добавлять в конец.
Вот примерный вариант:
let ul = document.querySelector('#elem')
//Ниже варианты обращения к li
let li = ul.firstElementChild.cloneNode(true)
let liID = document.getElementById('li')
let liAll = document.querySelectorAll('li')
// let liTag = document.getElementsByTagName('li') // HTMLcollection тоже самое что и liAll
// let liCh = ul.children // HTMLcollection тоже самое что и liAll
ul.addEventListener('click', foo)
function foo(ev) {
console.log(ev.target) // <li>
console.log("Put all <li> together version: ", ev.target === liAll ); // false при обращении к HTMLcollection
console.log("Personal index version: ", ev.target === liAll[0]); // true только если кликнуть на указанный индекс
console.log("Personal <li id='li'> version: ", ev.target === liID); // true только если кликнуть на указанный ID
if (ev.target.nodeName === 'LI' && ev.target.parentElement == ul) {
ev.target.innerHTML += '?'
}
let li1 = document.createElement('li');
li1.innerHTML = 'text'
this.append(li1)
}
ul {
padding: 30px;
border: 1px solid #8f93b6;
}
li {
list-style-type: none;
margin-bottom: 20px;
border: 1px dashed black;
}
<ul id="elem">
<li id="li">text</li>
<li>text</li>
<li>text</li>
<li>text</li>
<li>text</li>
</ul>
const ul = document.querySelector('#elem')
function foo(ev) {
if (ev.target.tagName === 'LI') {
return ev.target.innerHTML += '?'
}
const li = ul.firstElementChild.cloneNode(true)
this.append(li)
}
ul.addEventListener('click', foo)
ul {
padding: 30px;
border: 1px solid #8f93b6;
}
li {
list-style-type: none;
margin-bottom: 20px;
border: 1px dashed black;
}
<ul id="elem">
<li id="li">text</li>
<li>text</li>
<li>text</li>
<li>text</li>
<li>text</li>
</ul>
Уникальный id для ul и потом смотреть, являются ли li дочерними. Почему один добавляется уже написали в других ответах.. Так же другие ответы работают не корректно у @rusgeli при клике на li добавляется элемент.. У @webDev_ если кликнули по первому li, затем клонируется и вставляется с уже добавленным ?.. Без фамильярности вряд ли.. Всё таки вы работаете с вложенными элементами. Вопрос только в том, какой путь идентификации li выбрать..
let ul = document.querySelector('#elem');
ul.addEventListener('click', function(e){
let elem = e.target;
let parentId = elem.parentNode.getAttribute('id');
if (parentId == "elem") {
elem.innerHTML += "?";
} else if (elem.getAttribute('id') == "elem") {
let li = document.createElement('li');
li.innerHTML = 'text';
this.append(li);
}
});
ul {
padding: 30px;
border: 1px solid #8f93b6;
}
li {
list-style-type: none;
margin-bottom: 20px;
border: 1px dashed black;
}
<ul id="elem">
<li>text</li>
<li>text</li>
<li>text</li>
<li>text</li>
<li>text</li>
</ul>