Listener di eventi clic JavaScript sulla classe


220

Attualmente sto provando a scrivere un po 'di JavaScript per ottenere l'attributo della classe su cui è stato fatto clic. So che per farlo nel modo corretto, dovrei usare un listener di eventi. Il mio codice è il seguente:

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

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

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

Mi aspettavo di ricevere una finestra di avviso ogni volta che facevo clic su una delle classi per dirmi l'attributo, ma sfortunatamente non funziona. Qualcuno può aiutare, per favore?

( Nota : posso farlo abbastanza facilmente jQueryma NON vorrei usarlo )


2
Si è verificato un problema con il codice che aggiunge il listener di eventi. addEventListener accetta il nome dell'evento ('clic'), il riferimento alla funzione (non il risultato della funzione come è ora chiamando myFunction () con parentesi) e un flag per indicare il bubbling dell'evento. La chiamata addEventListener dovrebbe apparire come: elem.addEventListener ('click', myFunction, false) e classname è un tipo NodeList. È necessario eseguire il ciclo su tutti gli elementi e collegare l'ascoltatore a ciascuno nell'elenco.
Joey Guerra,

Risposte:


373

Questo dovrebbe funzionare. getElementsByClassNamerestituisce un array di array-come oggetto (vedi modifica) degli elementi corrispondenti ai criteri.

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 fa la parte del ciclo per te, che devi fare in JavaScript.

Se hai il supporto ES6 puoi sostituire l'ultima riga con:

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

Nota: i browser meno recenti (come IE6, IE7, IE8) non supportano getElementsByClassNamee quindi ritornano undefined.


EDIT: correzione

getElementsByClassNamenon restituisce un array, ma HTMLCollection nella maggior parte o un NodeList in alcuni browser (riferimento Mozilla ). Entrambi questi tipi sono simili ad array (nel senso che hanno una proprietà length e gli oggetti sono accessibili tramite il loro indice), ma non sono rigorosamente un array o ereditati da un array. (intendendo che altri metodi che possono essere eseguiti su un array non possono essere eseguiti su questi tipi)

Grazie all'utente @ Nemo per averlo segnalato e avermi fatto scavare per capire appieno.


6
Funziona perfettamente. Grazie. In realtà non mi rendevo conto che jQuery faceva il looping. Grande aiuto Anudeep. Ecco la tua risposta attiva: jsfiddle.net/LWda3/2
30secondstosam

2
document.getElementsByClassNamein realtà restituisce sempre un array, anche se solo un elemento soddisfa i criteri
Guilherme Sehn,

Attento anche se il primo elemento dell'array sono tutti gli elementi dom. Quindi inizia il tuo ciclo con 1
Vishal Sakaria il

11
stackoverflow.com/a/13258908/1333493 "document.getElementsByClassName non restituisce un array. Restituisce un elenco di nodi che viene attraversato come un file XML."
Nemo,

9
Array.from()ha un secondo parametro che è una funzione della mappa in modo da poter scrivere quanto sopra (supponendo il supporto es6) Array.from(classname, c => c.addEventListener('click', myFunction));.
Kilmazing

12

* Questo è stato modificato per consentire ai bambini della classe target di attivare gli eventi. Vedi in fondo alla risposta per i dettagli. *

Una risposta alternativa per aggiungere un listener di eventi a una classe in cui gli elementi vengono aggiunti e rimossi frequentemente. Questo si ispira alla onfunzione di jQuery in cui è possibile passare un selettore per un elemento figlio su cui l'evento è in ascolto.

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/

Questo ascolterà i clic sui figli basedell'elemento e se la destinazione di un clic ha un genitore corrispondente al selettore, verrà gestito l'evento di classe. Puoi aggiungere e rimuovere elementi a tuo piacimento senza dover aggiungere più listener di clic ai singoli elementi. Questo li catturerà tutti anche per gli elementi aggiunti dopo l'aggiunta di questo ascoltatore, proprio come la funzionalità jQuery (che immagino sia in qualche modo simile sotto il cofano).

Questo dipende dalla propagazione degli eventi, quindi se si è stopPropagationsull'evento da qualche altra parte, questo potrebbe non funzionare. Inoltre, la closestfunzione ha apparentemente alcuni problemi di compatibilità con IE (cosa no?).

Questo potrebbe essere trasformato in una funzione se è necessario eseguire questo tipo di azione ascoltando ripetutamente, ad esempio

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

=========================================
MODIFICA: Questo post originariamente utilizzava la matchesfunzione per Elementi DOM sulla destinazione dell'evento, ma ciò ha limitato le destinazioni degli eventi solo alla classe diretta. È stato aggiornato per utilizzare closestinvece la funzione, consentendo anche agli eventi sui bambini della classe desiderata di attivare gli eventi. Il matchescodice originale si trova sul violino originale: https://jsfiddle.net/u6oje7af/23/


3

Puoi usare il codice qui sotto:

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

Dovrò provarlo, è un approccio unico che potrebbe effettivamente essere più facile da mantenere ed eseguire meglio del looping!
Cliff Helsel,

4
se l'elemento ha più classi, dovresti controllare il valore corretto in quei campi es. classi e ordine. Preferirei andareevt.target.classList.contains('databox')
honk31

8
Questo mi sembra estremamente inefficiente. Ogni singolo evento sul corpo passerebbe attraverso questa funzione. Cosa c'è di così difficile da mantenere in un ciclo?
JosefAssad,

Questo è molto inefficiente, passeresti attraverso ogni elemento come diceva @JosefAssad.
nullwriter,

3

Con JavaScript moderno si può fare così:

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. Ottiene tutti gli elementi in base al nome della classe
  2. Passa in rassegna tutti gli elementi usando forEach
  3. Allega un listener di eventi su ciascun elemento
  4. Utilizza event.targetper recuperare più informazioni per l'elemento specifico
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.