在 NodeList 上添加事件监听器

IT技术 javascript addeventlistener nodelist
2021-03-11 08:43:33

NodeList 是否支持 addEventListener。如果不是,将 EventListener 添加到 NodeList 的所有节点的最佳方法是什么。目前我正在使用如下所示的代码片段,有没有更好的方法来做到这一点。

var ar_coins = document.getElementsByClassName('coins');
for(var xx=0;xx < ar_coins.length;xx++)
{
        ar_coins.item(xx).addEventListener('dragstart',handleDragStart,false);
}
6个回答

如果不循环遍历每个元素,就没有办法做到这一点。当然,您可以编写一个函数来为您执行此操作。

function addEventListenerList(list, event, fn) {
    for (var i = 0, len = list.length; i < len; i++) {
        list[i].addEventListener(event, fn, false);
    }
}

var ar_coins = document.getElementsByClassName('coins');
addEventListenerList(ar_coins, 'dragstart', handleDragStart); 

或更专业的版本:

function addEventListenerByClass(className, event, fn) {
    var list = document.getElementsByClassName(className);
    for (var i = 0, len = list.length; i < len; i++) {
        list[i].addEventListener(event, fn, false);
    }
}

addEventListenerByClass('coins', 'dragstart', handleDragStart); 

而且,虽然您没有询问 jQuery,但这是 jQuery 特别擅长的东西:

$('.coins').on('dragstart', handleDragStart);
@SalmanPK - 这在这里无关紧要。的结果getElementsByClassName()立即使用而不存储,因此在使用时没有机会更改。
2021-04-17 08:43:33
小心,getElementsByClassName返回一个活动节点列表。
2021-05-09 08:43:33

我能想到的最好的办法是:

const $coins = document.querySelectorAll('.coins')
$coins.forEach($coin => $coin.addEventListener('dragstart', handleDragStart));

请注意,这使用了 ES6 特性,因此请确保先将其转译!

美味的... :-)
2021-04-18 08:43:33
谢谢@okay56k,我更新了答案以反映这一点。
2021-04-22 08:43:33
超级干净 - 两年过去了,通过更多浏览器 ES6 支持减少了转译的需要。
2021-04-24 08:43:33

实际上一种方法可以在没有循环的情况下做到这一点

[].forEach.call(nodeList,function(e){e.addEventListener('click',callback,false)})

这种方式用于我的单行助手库之一 - nanoQuery

即使你认为它仍然是一个循环,这也是非常糟糕的。谢谢你。
2021-04-24 08:43:33
也许它可以为您节省几次击键次数,但需要下一位开发人员多花几分钟时间来理解。净亏损。
2021-04-24 08:43:33
在我的用例中,此方法相对于传统的 for 循环仅节省了 5 次击键。然而,我喜欢不必定义任何迭代变量……而且,嘿,节省 5 次击键仍然是一件事情。
2021-05-08 08:43:33
这不使用循环控制结构和奇数变量。
2021-05-17 08:43:33
仅供参考,现在是 2018 年,NodeLists 在大多数浏览器中都是可迭代的nodeList.foreach(el => el.addEventListener('click', callback))对于大多数人来说应该足够了。如果没有,ES6 允许我们轻松地将类似数组的对象“扩展”为实际的数组。所以像这样:也 [...nodeList].foreach应该工作。
2021-05-17 08:43:33

最简单的例子是将此功能添加到 NodeList

NodeList.prototype.addEventListener = function (event_name, callback, useCapture)
{
    for (var i = 0; i < this.length; i++)
    {
      this[i].addEventListener(event_name, callback, useCapture);
    }
};

现在你可以这样做:

document.querySelectorAll(".my-button").addEventListener("click", function ()
{
    alert("Hi");
});

同样的方法,你可以做一个forEach循环

NodeList.prototype.forEach = function (callback)
{
    for (var i = 0; i < this.length; i++)
    {
      callback(this[i], i);
    }
};

使用:

document.querySelectorAll(".buttons").forEach(function (element, id)
{
    input.addEventListener("change", function ()
    {
        alert("button: " + id);
    });
});

编辑:请注意 NodeList.prototype.forEach 自 2016 年 11 月以来在 FF 中一直存在。虽然没有 IE 支持

在 es6 中,您可以使用 Array.from 从节点列表中创建一个数组,例如

ar_coins = document.getElementsByClassName('coins');
Array
 .from(ar_coins)
 .forEach(addEvent)

function addEvent(element) {
  element.addEventListener('click', callback)
}

或者只使用箭头函数

Array
  .from(ar_coins)
  .forEach(element => element.addEventListener('click', callback))
您的箭头函数在最后需要一个右括号才能工作。干杯。
2021-04-20 08:43:33