如何为具有相同类名的多个按钮添加事件侦听器?

8
我正在使用JavaScript构建一个决策树,但在这个项目中没有jQuery可用。
我想要在决策树中的任何位置(隐藏或显示在页面上的任何地方)放置具有相同类名的按钮。JS侧的监听器将运行一个函数。
这是我用于基于ID的监听器的代码。它工作得很好,但我需要能够使用相同类或名称的多个按钮。虽然我看过一些例子,但无法使其正常运行。
function q1a1() {
var q1a1button = document.getElementById("q1answer1");
        if(q1a1button.addEventListener){
q1a1button.addEventListener("click", function() { q1answer1();}, false);
        } else if(q1a1button.attachEvent){
q1a1button.attachEvent("onclick", function() { q1answer1();});
}
};

if(window.addEventListener){
    window.addEventListener("load", q1a1, false);
        } else if(window.attachEvent){
    window.attachEvent("onload", q1a1);
        } else{
    document.addEventListener("load", q1a1, false);                
}

function q1answer1() {          

//DO SOME STUFF
                                            }

这也需要在尽可能多的IE版本中运行。对于单个类处理,我正在使用querySelectorAll。


只需使用querySelectorAll()遍历具有该类的元素,大致包装您已经拥有的代码循环即可。您还可以将单个事件附加到body上,并查看(e.target||e.srcElement).className以决定如何在调用时间处理事件。 - dandavis
querySelectorAll在ie8中可用。如果您需要支持低于ie8的浏览器,我为您感到遗憾。只需迭代元素数组,为每个元素添加事件监听器即可。 - ndugger
5个回答

9
你真正需要的是JavaScript事件委托。在你的情况下,你有BUTTON元素,我假设它们是<button>标签。现在你想知道何时点击其中一个按钮,然后运行一个函数:
if (document.addEventListener) {
    document.addEventListener("click", handleClick, false);
}
else if (document.attachEvent) {
    document.attachEvent("onclick", handleClick);
}

function handleClick(event) {
    event = event || window.event;
    event.target = event.target || event.srcElement;

    var element = event.target;

    // Climb up the document tree from the target of the event
    while (element) {
        if (element.nodeName === "BUTTON" && /foo/.test(element.className)) {
            // The user clicked on a <button> or clicked on an element inside a <button>
            // with a class name called "foo"
            doSomething(element);
            break;
        }

        element = element.parentNode;
    }
}

function doSomething(button) {
    // do something with button
}

在页面上任何出现 <button class="foo">...</button> 元素的地方,单击它或其中任何HTML标签都会运行 doSomething 函数。
更新:由于使用了事件委托,文档对象只注册了一个单击处理程序。如果通过 AJAX 调用创建了更多的 <button>,则无需在这些新的 <button> 上注册单击处理程序,因为我们利用了从用户单击的元素向文档对象本身冒泡的单击事件。

jQuery的on方法非常方便,但对于那些没有使用jQuery或者不想使用它的人来说,我编写了 Oxydizr,它利用HTML5 data-*属性。它允许你完全解耦行为、标记和样式。 - Greg Burghardt
@Greg Burghardt 如果您想要实现按钮被点击后改变颜色,但是没有唯一的ID或类名,我们该如何实现呢? - user1788736
我一直在寻找一种提取事件目标的方法。你的代码向我展示了如何做到这一点。非常感谢你,这对我帮助很大。 - Abhimanyu Shekhawat

4
如果您没有jQuery:
if (document.body.addEventListener){
    document.body.addEventListener('click',yourHandler,false);
}
else{
    document.body.attachEvent('onclick',yourHandler);//for IE
}

function yourHandler(e){
    e = e || window.event;
    var target = e.target || e.srcElement;
    if (target.className.match(/keyword/))
    {
        //an element with the keyword Class was clicked
    }
}

如果您使用像jQuery这样的跨浏览器库:
HTML:
<div class="myClass">sample</div>
<div class="myClass">sample 2</div>

JS:

function theFuncToCall(event){
  //func code
}

$(document).on('click', '.myClass', theFuncToCall);

jQuery在该组织内不可用(我无法使用它),因此感到沮丧和新的学习曲线。 :) - user3460707
必须链接到You Might Not Need jQuery :) - Greg Burghardt

1
var buttons = document.querySelectorAll(".MyClassName");
var i = 0, length = buttons.length;
for (i; i < length; i++) {
    if (document.addEventListener) {
        buttons[i].addEventListener("click", function() {
            // use keyword this to target clicked button
        });
    } else {
        buttons[i].attachEvent("onclick", function() {
            // use buttons[i] to target clicked button
        });
    };
};

1
这个答案可能有点过度,但它应该向你展示了如何以“现代”的方式构建你的代码,即使你仍然针对旧浏览器。
编写代码以添加事件监听器,使新旧浏览器之间的差异最小化。如果需要反向操作,请使用以下代码。编写您的点击处理程序并将其包装在一个函数中,以仅选择具有正确类别的按钮的单击。将此作为侦听器添加到公共祖先节点。保留HTML标签。
  1. 编写代码以添加事件监听器,使新旧浏览器之间的差异最小化

    var listen = (function () { // 将返回用于unlisten的处理程序
        if (window.addEventHandler) {
            return function (node, type, handler) {
                node.addEventListener(type, handler);
                return handler;
            };
        } else if (window.attachEvent) {
            return function (node, type, handler) {
                var fn = function (e) {
                    if (!e) {
                        e = window.event;
                    }
                    if (!e.target && e.srcElement) {
                        e.target = e.srcElement;
                    }
                    return handler.call(this, e);
                };
                node.attachEvent('on' + type, fn);
                return fn;
            };
        } else {
            throw new Error('Events not supported in this environment');
            // or
         // return function ... node['on' + type] = function () { ... };
        }
    }());
    

    如果需要反向操作,请使用以下代码

    var unlisten = (function () { // 使用listen提供的处理程序
        if (window.removeEventListener) {
            return function (node, type, handler) {
                node.removeEventListener(type, handler);
            };
        } else if (window.detachEvent) {
            return function (node, type, handler) {
                node.detachEvent('on' + type, handler);
            };
        } else {
            throw new Error('Events not supported in this environment');
            // or
         // return function ... node['on' + type] = null;
        }
    }());
    
  2. 编写您的点击处理程序

    function clickHandler(e) {
        // do stuff
    }
    
  3. 将您的单击处理程序包装在一个函数中,以选择具有正确类别的按钮的单击

    function wrappedClickHandler(e) {
        var tokens, i;
        if (e.target.tagName !== 'INPUT' && e.target.tagName !== 'BUTTON') {
            return;
        }
        tokens = (e.target.className || '').split(' ');
        for (i = 0; i < tokens.length; ++i) {
            if (tokens[i] === 'theClassTokenWeWant') {
                return clickHandler.call(this, e);
                // or
             // return clickHandler.call(e.target, e);
            }
        }
    }
    
  4. 将此作为侦听器添加到公共祖先节点

    var h = listen(document, 'click', wrappedClickHandler);
    // .. 如果需要的话
    unlisten(document, 'click', h);
    

1

简化编写事件委托函数的方法是将其添加到按钮容器中吗?例如,

// Select Container Element
const questionContainer = document.querySelector(".container");

// Listen For Clicks Within Container
questionContainer.onclick = function (event) {
    // Prevent default behavior of button
    event.preventDefault();

    // Store Target Element In Variable
    const element = event.target;

    // If Target Element Is a Button
    if (element.nodeName === 'BUTTON') {
        // Event Code
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接