Слушатель событий щелчка 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но я НЕ хотел бы его использовать )

30secondstosam
источник
2
Есть проблема с кодом, который добавляет прослушиватель событий. addEventListener принимает имя события ('click'), ссылку на функцию (а не результат функции, как сейчас, вызывая myFunction () с паренами) и флаг, указывающий на всплывающее событие. Вызов addEventListener должен выглядеть следующим образом: elem.addEventListener ('click', myFunction, false), а имя класса является типом NodeList. Нужно перебрать все элементы и прикрепить слушателя к каждому из списка.
Джои Герра

Ответы:

373

Это должно работать. getElementsByClassNameвозвращает массив Array-подобный объект (см. редактирование) элементов, соответствующих критериям.

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.


РЕДАКТИРОВАТЬ: Исправление

getElementsByClassNameне возвращает массив, но HTMLCollection в большинстве или NodeList в некоторых браузерах ( ссылка на Mozilla ). Оба эти типа являются Array-Like (что означает, что они имеют свойство length и объекты могут быть доступны через их индекс), но не являются строго Array или наследуются от Array. (имеется в виду, что другие методы, которые могут быть выполнены на массиве, не могут быть выполнены для этих типов)

Спасибо пользователю @ Nemo за указание на это и за то, что я закопался, чтобы полностью понять.

Анудип Булла
источник
6
Это работает отлично. Спасибо. Я на самом деле не понимал, что JQuery делает цикл. Великая помощь Анудип. Вот ваш рабочий ответ: jsfiddle.net/LWda3/2
30secondstosam
2
document.getElementsByClassNameфактически всегда возвращает массив, даже если только один элемент соответствует критериям
Гильерме Сен
Осторожно, хотя первый элемент массива - это все элементы dom. Так что начните свой цикл с 1
Вишал Сакария
11
stackoverflow.com/a/13258908/1333493 «document.getElementsByClassName не возвращает массив. Он возвращает список узлов, которые пересекаются как XML-файл».
Немо,
9
Array.from()имеет второй параметр, который является функцией отображения, поэтому вышеприведенное (при условии поддержки es6) можно записать Array.from(classname, c => c.addEventListener('click', myFunction));.
Kilmazing
12

* Это было отредактировано, чтобы позволить детям целевого класса вызывать события. Смотрите в нижней части ответа для деталей. *

Альтернативный ответ для добавления прослушивателя событий в класс, где элементы часто добавляются и удаляются. Это вдохновлено onфункцией jQuery, где вы можете передать селектор для дочернего элемента, который прослушивает событие.

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
  }
});

Скрипка: 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);
    }
  });
}

================================================
РЕДАКТИРОВАТЬ: Этот пост первоначально использовал matchesфункцию для Элементы DOM на цели события, но это ограничивало цели событий только прямым классом. Он был обновлен для использования closestфункции вместо этого, что позволяет событиям дочернего класса желаемого класса также инициировать события. Оригинальный matchesкод можно найти на оригинальной скрипке: https://jsfiddle.net/u6oje7af/23/

obermillerk
источник
3

Вы можете использовать код ниже:

document.body.addEventListener('click', function (evt) {
    if (evt.target.className === 'databox') {
        alert(this)
    }
}, false);
Раджат Кумар
источник
Я должен попробовать это, это уникальный подход, который на самом деле легче поддерживать и выполнять лучше, чем зацикливание!
Клифф Хелсел
4
если элемент имеет несколько классов, вы должны проверить правильность значения в этих полях, например. занятия и порядок. Я предпочел быevt.target.classList.contains('databox')
Honk31
8
Это кажется дико неэффективным для меня. Каждое отдельное событие на теле проходит через эту функцию. Что так сложно поддерживать в петле?
JosefAssad
Это очень неэффективно, вы должны пройти через каждый элемент, как сказал @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для получения дополнительной информации для конкретного элемента
В. Самбор
источник