Attach a listener to multiple children

I am trying to get rid of jquery from my page and rewrite some functions in pure js. There are 2 lists with a class containing several li elements. Each li element must have an action on click to add the 'active' class to it. In jquery, this is very simple:

$('.work li').on('click', function () {
            var that = $(this);
            that.parent().find('li.active').removeClass('active');
            $(this).addClass('active');
        })

Is there a better solution in pure js and not something like this with nested loops:

    var lists = document.getElementsByClassName('work');
    for(var i=0; i<lists.length; i++){
       var children = lists[i].querySelectorAll('li');
       for(var j=0; j<children.length;j++){
        children[j].addEventListener();
       }
    }
+5
source share
6 answers

There are 2 lists with class work containing several li elements. Does each element need to have an action when clicked to add the 'active' class to it.

, li, querySelectorAll. querySelectorAll nodeList, , , . , .

:

var lists = document.querySelectorAll(".work li"), 
    doSomething = function() {
        [].map.call(lists, function(elem) { elem.classList.remove("active") });
        this.classList.add("active");
    };
[].map.call(lists, function(elem) {
    elem.addEventListener("click", doSomething, false);
});
li { cursor: pointer; }
.active { background-color: yellow; }
<ul class="work"><li>One</li><li>Two</li><li>Three</li></ul>
<ul class="work"><li>Four</li><li>Five</li><li>Six</li></ul>
Hide result

ul, event.target . , li, . ul s .


js, -

. . , , . , . , . javascript javascript jQuery :

$('.work li').on('click', function () { // internally will iterate and add listener to each li
    var that = $(this);
    that.parent().find('li.active').removeClass('active'); // go to parent and then find li
    $(this).addClass('active');
});

.

+5

li, event.target ( IE event.srcElement).

( - , , ). , ...

function clickHandler(e) {
  var elem, evt = e ? e : event;
  if (evt.srcElement) {
    elem = evt.srcElement;
  } else if (evt.target) {
    elem = evt.target;
  }

  // Filter out li tags
  if (elem && ('LI' !== elem.tagName.toUpperCase())) {
    return true;
  }

  console.log('You clicked: ' + elem.innerHTML)
  return true;
}

var lists = document.getElementsByClassName('work');
for (var i = 0; i < lists.length; i++) {
  var children = lists[i].addEventListener('click', clickHandler);
}
<ul class="work">
  <li>1.1</li>
  <li>1.2</li>
  <li>1.3</li>
  <li>1.4</li>
</ul>
<ul class="work">
  <li>2.1</li>
  <li>2.2</li>
  <li>2.3</li>
  <li>2.4</li>
</ul>
<ul class="work">
  <li>3.1</li>
  <li>3.2</li>
  <li>3.3</li>
  <li>3.4</li>
</ul>
Hide result
+3

. document.querySelectorAll? css, .

, - :

{
 liList = document.querySelectorAll('.work li');
 var i, n = liList.length;
 for (i=0; i<n; i++)
  liList[i].addEventListener(eventName, functionName, useCapture);
}
+2

querySelectorAll() - .

JSFiddle .

:

for (var item of document.querySelectorAll(".work li")) {
 item.addEventListener("click", function (evt) {
     evt.target.classList.add("active");
 }, false);
}

( forEach):

Array.prototype.forEach.call(document.querySelectorAll(".work li"), function(item) {
   item.addEventListener("click", function (evt) {
        evt.target.classList.add("active");
   }, false);
});

(JSFiddle) NodeList, querySelectorAll(".work li") Array.prototype.forEach .

(Jsfiddle) - , :

Array.prototype.forEach.call(document.querySelectorAll(".work li"), function(item) {
   item.addEventListener("click", function (evt) {
        evt.target.toggleActive = !evt.target.toggleActive;
       evt.target.classList[!!evt.target.toggleActive ? 'add' : 'remove']("active");
   }, false);
});

, , (Jsfiddle):

var currentActiveElement;
Array.prototype.forEach.call(document.querySelectorAll('.work li'), function(item) {
item.addEventListener('click', function(evt) {
  currentActiveElement && currentActiveElement.classList.remove('active');
  currentActiveElement = evt.target;
  currentActiveElement.classList.add('active');
 }, false);
});
+2

DOM, , . , :

eachClass('work', function(work) {
    eachSelector(work, 'li', function(li) {
        on(li, 'click', function() {
            eachChild(parent(li), active.remove);
            active.add(li);
        });
    });
});

eachClass, eachSelector, eachChild, parent on, - . 2-3 . , , .

function eachClass(cls, fn) {
    [].forEach.call(document.getElementsByClassName(cls), fn);
}

active? , :

function makeClassSetter(cls) {
    return {
        add: function(elt) { elt.classList.add(cls); },
        remove: function(elt) {elt.classList.remove(cls); }
    };
}
var active = makeClassSetter('active');

. , -. , , .

+1

I was also looking for a short but useful solution for this.

This is the best approach I came up with:

tag = document.querySelectorAll('.tag');

tag.forEach(element => {
  element.addEventListener("mouseover", aFunction);
});

function aFunction(){
  this.style.background = "grey";
}

querySelectorAll is a powerful method, foreach is always much shorter and easier to use when there is a use case. I prefer to name functions and add to them, although I suggest that you can easily replace this with another arrow function in foreach if you prefer

0
source

Source: https://habr.com/ru/post/1568753/


All Articles