Предложение ChrisG с атрибутами data-*
является лучшим решением. Этот ответ заключается в расширении аспекта события до решения.
Важный шаблон программирования, называемый делегированием событий, должен использоваться при наличии нескольких целей событий (т. Е. item - aka li.star
). Вместо того, чтобы каждый элемент прослушивал событие - назначьте их «родительский» элемент (т. Е. list - aka ul.stars
), чтобы прослушать событие для всех них. Выполнив следующее, вы можете использовать один элемент для прослушивания события, вызванного любым из его дочерних элементов (неограниченное количество).
Зарегистрируйте событие для элемента, который все соответствующие элементы (т.е. все li.star
- на данный момент для каждого из них будут называться item ) разделяют какобщий предок (ul.stars
- на данный момент упоминается как список )
Функция обратного вызова должна передавать объект события
Пример:
function starRate(event) {...
или
function starRate(e) {...
Используйте if/else if
операторы управления со свойствами объекта события для изоляции элементов. Наиболее важные свойства события:
.target
: всегда ссылается на фактический элемент, который был нажат, наведен на указатель мыши и т. Д. (Т. Е. item )
.currentTarget
: всегда ссылается на элемент, который прослушивает событие (т. Е. список )
Пример:
if (e.target !== e.currentTarget) {...
Интерпретируется как: "если элемент, для которого было инициировано событие НЕ элемент, прослушивающий событие ..."
См. Эту статью на Делегирование событий
Более подробная информация прокомментирована в демоверсии ниже Примечание: Событие в демоверсии mouseover
только потому, что все другие события указателя вызывают ту же функцию обратного вызова (то есть starRate()
).
// [list]
// Reference the element that is the parent of all stars (ul.stars)
const list = document.querySelector('.stars');
// [item]
// Collect all the stars into a NodeList (li.star)
const items = document.querySelectorAll('.star');
// [message]
// Reference the message display element (output.message)
const message = document.querySelector('.message')
// Register the mouseover event to the parent element
// The Event Object will reference [list] as e.currentTarget
list.addEventListener("mouseover", starRate);
// Assign to each [item] the attribute 'data-star-num'
// Set each 'data-star-num' value corresponding to it's index +1
items.forEach((star, index) => {
star.dataset.starNum = index + 1;
});
// Pass Event Object (e)
function starRate(e) {
// e.target is the actual element being hovered over [item]
// e.currentTarget is the element to which the event is registered to [list]
// if the hovered over element [item] IS NOT [list]...
if (e.target !== e.currentTarget) {
// and if the [item] has the attribute 'data-star-num'...
if (e.target.hasAttribute('data-star-num')) {
// get the value of that [item]'s 'data-star-num' value
// converting it to a real number is optional
let num = parseInt(e.target.dataset.starNum);
// Log value to console
console.log(num);
// Display value on [message]
message.textContent = num;
}
}
// Otherwise terminate function
// This statement also prevents the event from bubbling any further
return false;
}
ul {
list-style-type: none;
padding: 0;
}
.star {
display: inline-block;
color: #ddd;
font-size: 2.5em;
padding: 8px;
margin: 5px;
cursor: pointer
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
</head>
<body>
<ul class="stars">
<li class="star"><i class="fa fa-star" aria-hidden="true"></i></li>
<li class="star"><i class="fa fa-star" aria-hidden="true"></i></li>
<li class="star"><i class="fa fa-star" aria-hidden="true"></i></li>
<li class="star"><i class="fa fa-star" aria-hidden="true"></i></li>
<li class="star"><i class="fa fa-star" aria-hidden="true"></i></li>
</ul>
<output class="message">Message</output>
</body>
</html>