слушатель события не возвращает свойство объекта для всех типов событий - PullRequest
1 голос
/ 04 октября 2019

const stars=document.querySelectorAll('.star')
    const message=document.querySelector('.message')
    const mouseEvents=["mouseover", "mouseout", "click"]
    //creating star object
    //add event listeners as array
    
    
    stars.forEach((star, i)=> {
      star.starNum=(i+1)
      console.log(star.starNum)
      mouseEvents.forEach((event)=> {
        star.addEventListener(event, starRate)
      })
    })
    
    
    function starRate(e) {
      let num=e.target.starNum
      console.log(num)
    }
 ul {
      list-style-type: none;
      padding: 0;
    }
    
    .star {
      display: inline-block;
      color: #ddd;
      font-size: 2.5em;
    }
<!DOCTYPE html>
      <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title></title>
        <meta name="description" content="">
        <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">
        <link rel="stylesheet" href="styles.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>
        <div class="message">Message</div>
        
      </body>
    
      <script src="app.js"></script>
      
    </html>

Я применил несколько событий к каждому элементу звезды. Но всякий раз, когда я нажимаю или при наведении мыши на звезду, он не возвращает значение своего свойства starNum, как это предполагается из функции starRate . Он возвращает число только при наведении мыши на него. Почему это?

Ответы [ 2 ]

1 голос
/ 04 октября 2019

Предложение 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>
1 голос
/ 04 октября 2019

Свойство target интерфейса Event является ссылкой на объект, отправивший событие.

https://developer.mozilla.org/en-US/docs/Web/API/Event/target

Это означает, что у вас есть доступ кэлемент dom и не может получить доступ к желаемому свойству. Вы можете передать это свойство одним из двух способов.

Первый способ : Использование data-* атрибута Документация

Измените ваш HTML, чтобы включитьданные, которые вы хотите

 <li class="star" data-starnumber="1"><i class="fa fa-star" aria-hidden="true"></i></li>

В вашем javascript вы можете ссылаться на данные напрямую.

function starRate(e) {
  const num = e.target.dataset.starnumber;
  console.log(num);
}

Второй способ : привязать нужные данные к обратному вызову Документация

Вы можете привязать данные, которые вы хотите представить в вызове функции.

stars.forEach((star, i) => {
  star.starNum = i+1;
  console.log(star.starNum);
  mouseEvents.forEach((event) => {
    star.addEventListener(event, starRate.bind(null, star);
  });
});

function starRate(star, e) {
  const num = star.starNum;
  console.log(num);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...