Слухач подій клацання JavaScript на уроці


220

На даний момент я намагаюся написати якийсь JavaScript, щоб отримати атрибут класу, на який було натиснуто. Я знаю, що щоб зробити це правильно, я повинен використовувати слухач подій. Мій код такий:

var classname = document.getElementsByClassName("classname");

var myFunction = function() {
    var attribute = this.getAttribute("data-myattribute");
    alert(attribute);
};

classname.addEventListener('click', myFunction(), false);

Я очікував отримати поле сповіщення кожного разу, коли натискав на один із класів, щоб повідомити мені атрибут, але, на жаль, це не працює. Може хтось допоможе, будь ласка?

( Примітка - я можу досить легко зробити це , jQueryале я б НЕ як використовувати його )


2
Існує проблема з кодом, який додає слухача події. addEventListener приймає ім'я події ("натискання"), посилання на функцію (не результат функції, як зараз, зателефонувавши myFunction () з паролями) та прапор, який вказує на бульбашку подій. Виклик addEventListener повинен мати вигляд: elem.addEventListener ("натиснути", myFunction, помилково), а ім'я класу - це тип NodeList. Потрібно перенести всі елементи та приєднати слухача до кожного зі списку.
Joey Guerra

Відповіді:


373

Це має спрацювати. getElementsByClassNameповертає масив, схожий на масив (див. редагування) елементів, що відповідають критеріям.

var elements = document.getElementsByClassName("classname");

var myFunction = function() {
    var attribute = this.getAttribute("data-myattribute");
    alert(attribute);
};

for (var i = 0; i < elements.length; i++) {
    elements[i].addEventListener('click', myFunction, false);
}

jQuery робить циклічну частину для вас, яку вам потрібно зробити в простому JavaScript.

Якщо у вас є підтримка ES6, ви можете замінити останній рядок на:

    Array.from(elements).forEach(function(element) {
      element.addEventListener('click', myFunction);
    });

Примітка. Старі браузери (наприклад, IE6, IE7, IE8) не підтримують, getElementsByClassNameі вони повертаються undefined.


EDIT: Виправлення

getElementsByClassNameне повертає масив, але HTMLCollection у більшості, або NodeList у деяких браузерах ( Mozilla ref ). Обидва ці типи є Array-Like, (це означає, що вони мають властивість довжини і до об'єктів можна отримати доступ через їх індекс), але не є суворо Масивом або успадкованими від масиву. (тобто інші методи, які можна виконати на масиві, неможливо виконати для цих типів)

Дякуємо користувачеві @ Nemo за те, що вказав на це і змусив мене розібратися, щоб повністю зрозуміти.


6
Це прекрасно працює. Дякую. Я насправді не усвідомлював, що jQuery зробив циклічний цикл. Чудово допомагає Анудеп. Ось ваш робочий відповідь: jsfiddle.net/LWda3/2
30secondstosam

2
document.getElementsByClassNameнасправді завжди повертає масив, навіть якщо лише один елемент відповідає критеріям
Guilherme Sehn

Обережно, хоча першим елементом масиву є всі елементи dom. Тож почніть свій цикл із 1
Вішал Сакарія

11
stackoverflow.com/a/13258908/1333493 "document.getElementsByClassName не повертає масив. Він повертає список вузлів, який проходить як XML-файл."
Немо

9
Array.from()має другий параметр, який є функцією карти, тому вищезазначене (за умови підтримки es6) могло бути записане Array.from(classname, c => c.addEventListener('click', myFunction));.
Кілмазінг

12

* Це було відредаговано, щоб діти цільового класу могли викликати події. Деталі див. У нижній частині відповіді. *

Альтернативна відповідь, щоб додати слухача подій до класу, де елементи часто додаються та видаляються. Це натхнене функцією jQuery, onде ви можете передати селектор для дочірнього елемента, який подія слухає.

var base = document.querySelector('#base'); // the container for the variable content
var selector = '.card'; // any css selector for children

base.addEventListener('click', function(event) {
  // find the closest parent of the event target that
  // matches the selector
  var closest = event.target.closest(selector);
  if (closest && base.contains(closest)) {
    // handle class event
  }
});

Fiddle: https://jsfiddle.net/u6oje7af/94/

Це послухає натискання на діти baseелемента, і якщо в цілі клацання є батько, який відповідає селектору, подія класу буде оброблятися. Ви можете додавати та видаляти елементи, як вам подобається, не потрібно додавати більше слухачів кліків до окремих елементів. Це зачепить їх навіть за елементи, додані після того, як цей слухач був доданий, подібно до функціональності jQuery (який, я думаю, дещо схожий під капотом).

Це залежить від подій, що поширюються, тож якщо ви stopPropagationподії десь в іншому місці, це може не спрацювати. Крім того, у closestфункції є деякі проблеми сумісності з IE, мабуть (що ні?).

Це може бути перетворено на функцію, якщо вам потрібно виконувати прослуховування цього типу кілька разів, наприклад

function addChildEventListener(base, eventName, selector, handler) {
  base.addEventListener(eventName, function(event) {
    var closest = event.target.closest(selector);
    if (closest && base.contains(closest)) {
      // passes the event to the handler and sets `this`
      // in the handler as the closest parent matching the
      // selector from the target element of the event
      handler.call(closest, event);
    }
  });
}

===========================================
EDIT: Ця публікація спочатку використовувала цю matchesфункцію для Елементи DOM на меті події, але це обмежило цілі подій лише прямим класом. Він був оновлений, щоб використовувати closestфункцію замість цього, дозволяючи подіям на дітей потрібного класу ініціювати події. Оригінальний matchesкод можна знайти в оригінальній скрипці: https://jsfiddle.net/u6oje7af/23/


3

Ви можете використовувати код нижче:

document.body.addEventListener('click', function (evt) {
    if (evt.target.className === 'databox') {
        alert(this)
    }
}, false);

Мені доведеться спробувати це, це унікальний підхід, який насправді може бути простішим у обслуговуванні та виконанні краще, ніж циклічне!
Кліф

4
якщо в елементі є кілька класів, вам доведеться перевірити правильність значення в цих полях, наприклад. класи та порядок. Я б швидше поїхавevt.target.classList.contains('databox')
honk31

8
Це здається мені дико неефективним. Кожна окрема подія на тілі переходила б через цю функцію. Що так важко підтримувати в циклі?
ЙозефАссад

Це дуже неефективно, ви проходили б кожен елемент, як сказав @JosefAssad.
nullwriter

3

З сучасним JavaScript це можна зробити так:

const divs = document.querySelectorAll('.a');

divs.forEach(el => el.addEventListener('click', event => {
  console.log(event.target.classList[1]);
}));
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Example</title>
  <style>
    .a {
      background-color:red;
      height: 33px;
      display: flex;
      align-items: center;
      margin-bottom: 10px;
      cursor: pointer;
    }
    
    .b {
      background-color:#00AA00;
      height: 50px;
      display: flex;
      align-items: center;
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <div class="a a-1">1</div>
  <div class="b">2</div>
  <div class="a a-2">11</div>
</body>
</html>

  1. Отримує всі елементи за назвою класу
  2. Петлі над усіма елементами за допомогою forEach
  3. До кожного елемента приєднайте слухача подій
  4. Використовує event.targetдля отримання додаткової інформації для конкретного елемента
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.