类上的 JavaScript 单击事件侦听器

Posted

技术标签:

【中文标题】类上的 JavaScript 单击事件侦听器【英文标题】:JavaScript click event listener on class 【发布时间】:2013-11-08 10:17:52 【问题描述】:

我目前正在尝试编写一些 javascript 来获取已单击类的属性。我知道要以正确的方式做到这一点,我应该使用事件侦听器。 我的代码如下:

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

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

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

我希望每次单击其中一个类来告诉我属性时都会收到一个警告框,但不幸的是这不起作用。有人可以帮忙吗?

注意 - 我可以在jQuery 中轻松做到这一点,但我喜欢使用它

【问题讨论】:

添加事件侦听器的代码有问题。 addEventListener 采用事件名称('click')、对函数的引用(不是现在通过使用括号调用 myFunction() 得到的函数结果)和一个指示事件冒泡的标志。 addEventListener 调用应如下所示: elem.addEventListener('click', myFunction, false) 并且 classname 是 NodeList 类型。需要遍历所有元素并将侦听器附加到列表中的每个元素。 【参考方案1】:

这应该可行。 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 ref)。这两种类型都是类数组(意味着它们具有长度属性并且可以通过它们的索引访问对象),但不是严格意义上的数组或继承自数组(意味着可以在数组上执行的其他方法不能对这些类型执行)。

感谢用户@Nemo 指出这一点并让我深入了解。

【讨论】:

这非常有效。谢谢你。我实际上并没有意识到 jQuery 进行了循环。伟大的帮助阿努迪普。这是您的工作答案:jsfiddle.net/LWda3/2 document.getElementsByClassName 实际上总是返回一个数组,即使只有一个元素符合条件 小心,虽然数组的第一个元素是所有 dom 元素。所以用 1 开始你的 for 循环 ***.com/a/13258908/1333493 "document.getElementsByClassName 不返回一个数组。它返回一个像 XML 文件一样遍历的节点列表。" Array.from() 有第二个参数,它是一个映射函数,所以上面的(假设支持 es6)可以写成Array.from(classname, c =&gt; c.addEventListener('click', myFunction));【参考方案2】:

使用现代 JavaScript 可以这样做:

const divs = document.querySelectorAll('.a');

divs.forEach(el => el.addEventListener('click', event => 
  console.log(event.target.getAttribute("data-el"));
));
<!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" data-el="1">1</div>
  <div class="b" data-el="no-click-handler">2</div>
  <div class="a" data-el="3">11</div>
</body>
</html>
    按类名获取所有元素 使用 forEach 遍历所有元素 在每个元素上附加一个事件监听器 使用event.target 检索特定元素的更多信息

【讨论】:

这是我使用的,但我不能认为这个答案很有用,因为你偏离了问题中的功能试图做的事情。您应该真正更新您的答案以提取数据属性值而不是类名。 @Mark 谢谢 :) 我已根据您的要求进行了更新。祝你有美好的一天! 对我来说效果很好??【参考方案3】:

* 对此进行了编辑,以允许目标类的子级触发事件。有关详细信息,请参阅答案底部。 *

将事件侦听器添加到经常添加和删除项目的类的替代答案。这受到 jQuery 的 on 函数的启发,您可以在其中为事件正在侦听的子元素传递选择器。

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

=========================================== 编辑:这篇文章最初对事件目标上的 DOM 元素使用了 matches 函数,但这将事件的目标限制为仅直接类。它已更新为使用 closest 函数,从而允许所需类的子级事件也触发事件。原始matches 代码可以在原始小提琴中找到: https://jsfiddle.net/u6oje7af/23/

【讨论】:

【参考方案4】:

您可以使用下面的代码:

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

【讨论】:

我必须尝试一下,这是一种独特的方法,实际上可能比循环更容易维护和执行! 如果元素有多个类,您必须检查该字段中的正确值,例如。班级和秩序。我宁愿去evt.target.classList.contains('databox') 这对我来说似乎非常低效。身体上的每一个事件都会通过这个函数。循环有什么难维护的? 这是非常低效的,你会像@JosefAssad 所说的那样遍历每个元素。 我完全不同意这里的每个人。如果您使用 element.addEventListener('click', event => 将事件添加到元素,javascript 将在内部检查每次点击。如果将事件添加到类的所有元素 Javascript 将运行等效的检查实例每次点击,而上述方法每次点击只会查找一次。【参考方案5】:

您可以使用 querySelectorAll 来选择所有类并循环访问它们以分配 eventListener。 if 条件检查它是否包含类名。

const arrClass = document.querySelectorAll(".className");
for (let i of arrClass) 
  i.addEventListener("click", (e) => 
    if (e.target.classList.contains("className")) 
        console.log("Perfrom Action")
    
  )

【讨论】:

除非您怀疑 className 会动态更改,否则您不必重新检查 even 目标的 className。【参考方案6】:

另外考虑如果你点击一个按钮,事件监听器的目标不一定是按钮本身,而是你点击的按钮内的任何内容。您可以使用 currentTarget 属性引用分配了侦听器的元素。这是现代 ES 中使用单个语句的一个很好的解决方案:

    document.querySelectorAll(".myClassName").forEach(i => i.addEventListener(
        "click",
        e => 
            alert(e.currentTarget.dataset.myDataContent);
        ));

【讨论】:

以上是关于类上的 JavaScript 单击事件侦听器的主要内容,如果未能解决你的问题,请参考以下文章

使用事件侦听器(Javascript、jQuery)将 BG 颜色更改为随机颜色?

我们如何在javascript中添加两个事件监听器的单击和击键

事件监听器,JavaScript

javascript基础:事件

View 元素上的事件监听器

JavaScript基础教程—处理事件