将侦听器附加到多个子元素

mja*_*sz1 5 javascript listener

我试图摆脱我页面中的jquery,并将某些功能重写为纯js。有2个班级工作清单,其中包含几个li元素。每个li元素都应具有单击动作,以向其添加“活动”类。在jQuery中,它非常简单:

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

在纯js中是否有更好的解决方案,而不是使用嵌套循环来做类似的事情:

    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();
       }
    }
Run Code Online (Sandbox Code Playgroud)

Ale*_*nts 5

querySelectorAll()是一个非常强大的工具。

我为你做了一个JSFiddle 。

代码仍然很好并且可读:

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

另一种方法是(如果您仍然想使用 forEach 进行迭代):

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

这里(JSFiddle)我们通过调用Array.prototype.forEach方法返回的NodeList进行交互querySelectorAll(".work li")

这里(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);
});
Run Code Online (Sandbox Code Playgroud)

最后,如果一次应该只有一个活动元素(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);
});
Run Code Online (Sandbox Code Playgroud)

  • 如果我正确理解你的问题。`querySelectorAll()` 返回一个对象 [NodeList](https://developer.mozilla.org/en-US/docs/Web/API/NodeList),女巫[不能完全被视为数组](https:// developer.mozilla.org/en-US/docs/Web/API/NodeList#Why_is_NodeList_not_an_Array.3F)。 (2认同)

Abh*_*lks 5

有2个班级工作清单,其中包含几个li元素。每个li元素都应具有单击动作,以向其添加“活动”类。

您可以通过将事件监听器添加到所li返回的所有上来创建全部功能querySelectorAll。所述querySelectorAll返回一个节点列表,而不是一个数组,所以需要将其以映射到迭代它。但是,请注意,我们仍在迭代该集合。

示例片段

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);
});
Run Code Online (Sandbox Code Playgroud)
li { cursor: pointer; }
.active { background-color: yellow; }
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)


实际上,您还可以使用事件委托并仅在上添加事件侦听器ul,然后使用event.target来处理例程。这比向每个事件添加事件侦听器要好,以防事件侦听li器很多。处理程序将与uls 一样多。


在纯js中是否有更好的解决方案,而不是使用嵌套循环来做类似的事情

并不是的。无论如何,您都必须遍历元素集。是的,爵士乐方面更好。在避免循环方面更好,没有。在效率方面更好,是的。将上面的普通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');
});
Run Code Online (Sandbox Code Playgroud)