向一个元素添加多个事件侦听器

IT技术 javascript html dom-events
2021-01-28 06:38:28

所以我的困境是我不想写两次相同的代码。一次用于单击事件,另一次用于touchstart事件。

这是原始代码:

document.getElementById('first').addEventListener('touchstart', function(event) {
    do_something();
    });

document.getElementById('first').addEventListener('click', function(event) {
    do_something(); 
    });

我怎样才能压缩这个?必须有一个更简单的方法!

6个回答

我知道这是一个老问题,但我认为有些人可能会发现这种方法很有用;它可以应用于任何类似的重复代码:

ES6

['click','ontouchstart'].forEach( evt => 
    element.addEventListener(evt, dosomething, false)
);

ES5

['click','ontouchstart'].forEach( function(evt) {
    element.addEventListener(evt, dosomething, false);
});
您正在执行 alertFunction(),并将它的返回值(未定义)分配给事件处理程序。不要执行函数(使用 () ),只需将函数名称/引用传递给 eventListener 函数。请注意,在我的示例中, dosomething 后面没有 ()。
2021-03-15 06:38:28
你可以使用类似的东西: document.querySelectorAll(selectors).forEach((element) => { ... });
2021-03-25 06:38:28
但是如何定位特定的选择器?
2021-04-10 06:38:28
当我尝试使用它时,我在你写“dosomething”的地方写的函数在加载页面时触发。这是为什么?即使整行是:burgerElement.addEventListener(event, alertFunction(), false)和 'burgerelement' 是var burgerElement = document.querySelector('.burger');
2021-04-12 06:38:28

也许你可以使用这样的辅助函数:

// events and args should be of type Array
function addMultipleListeners(element,events,handler,useCapture,args){
  if (!(events instanceof Array)){
    throw 'addMultipleListeners: '+
          'please supply an array of eventstrings '+
          '(like ["click","mouseover"])';
  }
  //create a wrapper to be able to use additional arguments
  var handlerFn = function(e){
    handler.apply(this, args && args instanceof Array ? args : []);
  }
  for (var i=0;i<events.length;i+=1){
    element.addEventListener(events[i],handlerFn,useCapture);
  }
}

function handler(e) {
  // do things
};

// usage
addMultipleListeners(
    document.getElementById('first'),
    ['touchstart','click'],
    handler,
    false);

[编辑十一月。2020 ] 这个答案已经很老了。我现在解决这个问题的方法是使用一个actions对象,其中每个事件类型指定处理程序,一个data-attribute用于指示应该对其执行哪个操作的元素和一个通用文档范围的处理程序方法(因此事件委托)。

const firstElemHandler = (elem, evt) =>
  elem.textContent = `You ${evt.type === "click" ? "clicked" : "touched"}!`;
const actions = {
  click: {
    firstElemHandler,
  },
  touchstart: {
    firstElemHandler,
  },
  mouseover: {
    firstElemHandler: elem => elem.textContent = "Now ... click me!",
    outerHandling: elem => {
      console.clear();
      console.log(`Hi from outerHandling, handle time ${
        new Date().toLocaleTimeString()}`);
    },
  }
};

Object.keys(actions).forEach(key => document.addEventListener(key, handle));

function handle(evt) {
  const origin = evt.target.closest("[data-action]");
  return origin &&
    actions[evt.type] &&
    actions[evt.type][origin.dataset.action] &&
    actions[evt.type][origin.dataset.action](origin, evt) ||
    true;
}
[data-action]:hover {
  cursor: pointer;
}
<div data-action="outerHandling">
  <div id="first" data-action="firstElemHandler">
    <b>Hover, click or tap</b>
  </div>
  this is handled too (on mouse over)
</div>

警告:该事件在句柄函数中不可用。我修复了这个错误pastebin.com/raw/Lrcdv1ws
2021-04-03 06:38:28

您可以只定义一个函数并传递它。匿名函数没有任何特别之处,所有函数都可以作为值传递。

var elem = document.getElementById('first');

elem.addEventListener('touchstart', handler, false);
elem.addEventListener('click', handler, false);

function handler(event) {
    do_something();
}

对于大量事件,这可能会有所帮助:

var element = document.getElementById("myId");
var myEvents = "click touchstart touchend".split(" ");
var handler = function (e) {
    do something
};

for (var i=0, len = myEvents.length; i < len; i++) {
    element.addEventListener(myEvents[i], handler, false);
}

06/2017 更新:

既然新的语言功能更广泛可用,您可以简化添加共享一个侦听器的有限事件列表。

const element = document.querySelector("#myId");

function handleEvent(e) {
    // do something
}
// I prefer string.split because it makes editing the event list slightly easier

"click touchstart touchend touchmove".split(" ")
    .map(name => element.addEventListener(name, handleEvent, false));

如果您想处理大量事件并且对每个侦听器有不同的要求,您还可以传递一个大多数人容易忘记的对象

const el = document.querySelector("#myId");

const eventHandler = {
    // called for each event on this element
    handleEvent(evt) {
        switch (evt.type) {
            case "click":
            case "touchstart":
                // click and touchstart share click handler
                this.handleClick(e);
                break;
            case "touchend":
                this.handleTouchend(e);
                break;
            default:
                this.handleDefault(e);
        }
    },
    handleClick(e) {
        // do something
    },
    handleTouchend(e) {
        // do something different
    },
    handleDefault(e) {
        console.log("unhandled event: %s", e.type);
    }
}

el.addEventListener(eventHandler);

05/2019 更新:

const el = document.querySelector("#myId");

const eventHandler = {
    handlers: {
        click(e) {
            // do something
        },
        touchend(e) {
            // do something different
        },
        default(e) {
            console.log("unhandled event: %s", e.type);
        }
    },
    // called for each event on this element
    handleEvent(evt) {
        switch (evt.type) {
            case "click":
            case "touchstart":
                // click and touchstart share click handler
                this.handlers.click(e);
                break;
            case "touchend":
                this.handlers.touchend(e);
                break;
            default:
                this.handlers.default(e);
        }
    }
}

Object.keys(eventHandler.handlers)
    .map(eventName => el.addEventListener(eventName, eventHandler))
为什么string.split()当你可以在没有计算成本的情况下拥有一个字符串数组?
2021-03-19 06:38:28
@Pacerier 你是对的,这个错误很长一段时间都没有被注意到。您还可以定义一个普通对象而不是一个开关,并使用它的键来监听事件。如果您有一个对象,删除事件侦听器也会变得更容易,因为您不需要跟踪确切的侦听器而只需要传递该对象。
2021-03-28 06:38:28
@Torsten,但是您不需要字符串作为识别事件的第一个参数吗?如果是这样,它就违背了目的
2021-03-29 06:38:28
@mix3d 你是对的,定义一个数组更好,是生产代码的方法。拆分字符串在某些情况下很有用,但是在您从字符串中读取单词列表或需要频繁更改字符串并希望节省键入和读取几个字符的情况下。
2021-04-04 06:38:28

除非您的do_something函数实际上使用任何给定参数执行某些操作,否则您可以将其作为事件处理程序传递。

var first = document.getElementById('first');
first.addEventListener('touchstart', do_something, false);
first.addEventListener('click', do_something, false);
@PedroEsperança 不。我同意,能够传递像这样的字符串数组会很好,['touchstart','click']但没有这样的事情。
2021-03-18 06:38:28
我只是想可能有一种更快的方法.. 像:('touchstart, click', do_something, false)
2021-03-31 06:38:28