ChatGPT解决这个技术问题 Extra ChatGPT

Binding multiple events to a listener (without JQuery)?

While working with browser events, I've started incorporating Safari's touchEvents for mobile devices. I find that addEventListeners are stacking up with conditionals. This project can't use JQuery.

A standard event listener:

/* option 1 */
window.addEventListener('mousemove', this.mouseMoveHandler, false);
window.addEventListener('touchmove', this.mouseMoveHandler, false);

/* option 2, only enables the required event */
var isTouchEnabled = window.Touch || false;
window.addEventListener(isTouchEnabled ? 'touchmove' : 'mousemove', this.mouseMoveHandler, false);

JQuery's bind allows multiple events, like so:

$(window).bind('mousemove touchmove', function(e) {
    //do something;
});

Is there a way to combine the two event listeners as in the JQuery example? ex:

window.addEventListener('mousemove touchmove', this.mouseMoveHandler, false);

Any suggestions or tips are appreciated!


C
Collin Anderson

Some compact syntax that achieves the desired result, POJS:

   "mousemove touchmove".split(" ").forEach(function(e){
      window.addEventListener(e,mouseMoveHandler,false);
    });

Or directly ['mousemove', 'touchmove'].forEach(...)
+1 AND it doesn't need «ECMAScript 2015 arrow functions » extension! ;-)
@zuckerburg To start with, instead of hardcoding the array you hardcoded the strning and then splitted it, are you really sure that this is the way to go? Are you sure that this is the most readable way to write this? ['mousemove', 'touchmove'].forEach(function(event) { window.addEventListener(event, handler);}); would not only be way more readable but also would be much faster not having to split the string and then running a function for each item in the resulting array.
@IharobAlAsimi this code was written over 4 years ago, i've found my spacebar in that time. The string split was to relate to the OP's use of a string
@IharobAlAsimi I didn't write the code. You said it was unreadable. Clearly it's not since you and I are both capable of reading the code. This is like arguing over grammar. 99% of all programmers are able to read the code quite nicely
r
rogerdpack

In POJS, you add one listener at a time. It is not common to add the same listener for two different events on the same element. You could write your own small function to do the job, e.g.:

/* Add one or more listeners to an element
** @param {DOMElement} element - DOM element to add listeners to
** @param {string} eventNames - space separated list of event names, e.g. 'click change'
** @param {Function} listener - function to attach for each event as a listener
*/
function addListenerMulti(element, eventNames, listener) {
  var events = eventNames.split(' ');
  for (var i=0, iLen=events.length; i<iLen; i++) {
    element.addEventListener(events[i], listener, false);
  }
}

addListenerMulti(window, 'mousemove touchmove', function(){…});

Hopefully it shows the concept.

Edit 2016-02-25

Dalgard's comment caused me to revisit this. I guess adding the same listener for multiple events on the one element is more common now to cover the various interface types in use, and Isaac's answer offers a good use of built–in methods to reduce the code (though less code is, of itself, not necessarily a bonus). Extended with ECMAScript 2015 arrow functions gives:

function addListenerMulti(el, s, fn) {
  s.split(' ').forEach(e => el.addEventListener(e, fn, false));
}

A similar strategy could add the same listener to multiple elements, but the need to do that might be an indicator for event delegation.


Thank you for the sentence "It is not common to add the same listener for two different events on the same element." Sometimes (greener) devs need to hear this to know they're doing it right :)
Don't you mean "it is not UNcommon"?
@dalgard—it's more common now that touch devices are more common, but only for a limited number of events (such as mousemove and touchmove). That it is required shows the short sightedness of naming events after physical items, pointer move might have been more appropriate. It can be implemented by touch or other device. Before mice (or mouses) there were x/y wheels, some I've used had hand and foot wheels (1970s Stecometer). There are also track balls and spheres, some move in 3d.
@RobG: The API I'm dealing with is the DOM, and yes, its shortcomings are legion :) But it may also simply be a question of avoiding duplicate code in listeners that are similar.
@PedroFerreira—yes of course, probably more than half the browsers currently in use don't support arrow functions, but they're fun to play with and there is always Babel. ;-)
p
pmrotule

Cleaning up Isaac's answer:

['mousemove', 'touchmove'].forEach(function(e) {
  window.addEventListener(e, mouseMoveHandler);
});

EDIT

ES6 helper function:

function addMultipleEventListener(element, events, handler) {
  events.forEach(e => element.addEventListener(e, handler))
}

FYI: map != forEach
C
ChrisTheButcher

ES2015:

let el = document.getElementById("el");
let handler =()=> console.log("changed");
['change', 'keyup', 'cut'].forEach(event => el.addEventListener(event, handler));

Alternatively using the for...of loop
u
user3796876

For me; this code works fine and is the shortest code to handle multiple events with same (inline) functions.

var eventList = ["change", "keyup", "paste", "input", "propertychange", "..."];
for(event of eventList) {
    element.addEventListener(event, function() {
        // your function body...
        console.log("you inserted things by paste or typing etc.");
    });
}

Exactly what I am looking for. Thanks!
佚名

I have a simpler solution for you:

window.onload = window.onresize = (event) => {
    //Your Code Here
}

I've tested this an it works great, on the plus side it's compact and uncomplicated like the other examples here.


There is only one .onload possible. Perhaps you overwrite an old listener. Depending on your environment this can be a problem.
R
Reza Saadati

One way how to do it:

const troll = document.getElementById('troll'); ['mousedown', 'mouseup'].forEach(type => { if (type === 'mousedown') { troll.addEventListener(type, () => console.log('Mouse is down')); } else if (type === 'mouseup') { troll.addEventListener(type, () => console.log('Mouse is up')); } }); img { width: 100px; cursor: pointer; }

Troll


What's the point of using array and foreach if you're gonna do if (type === 'mousedown')?!?!
@Arad because you can only use that statement since type is the parameter of forEach(). So without the array and without the forEach function, type would not be defined.
No, I mean why not just do troll.addEventListener('mousedown', () => console.log('Mouse is down'));. Why do you need a forEach if you're going to check for each event type and attach a different event handler to it?! The whole point of using a forEach in this case is to attach the same event handler to multiple events, obviously.
S
Selvakumar Arumugam

AddEventListener take a simple string that represents event.type. So You need to write a custom function to iterate over multiple events.

This is being handled in jQuery by using .split(" ") and then iterating over the list to set the eventListeners for each types.

    // Add elem as a property of the handle function
    // This is to prevent a memory leak with non-native events in IE.
    eventHandle.elem = elem;

    // Handle multiple events separated by a space
    // jQuery(...).bind("mouseover mouseout", fn);
    types = types.split(" ");  

    var type, i = 0, namespaces;

    while ( (type = types[ i++ ]) ) {  <-- iterates thru 1 by 1

V
VityaSchel

You can also use prototypes to bind your custom function to all elements

Node.prototype.addEventListeners = function(eventNames, eventFunction){
    for (eventName of eventNames.split(' '))
        this.addEventListener(eventName, eventFunction);
}

Then use it

document.body.addEventListeners("mousedown touchdown", myFunction)

It's frowned upon to modify prototypes that you didn't create. For pet projects, go right ahead, but please don't ever do this in a package you intend on sharing with others.
D
DEV Tiago França
// BAD: One for each event - Repeat code
textarea.addEventListener('keypress', (event) => callPreview);
textarea.addEventListener('change', (event) => callPreview);

// GOOD: One run for multiple events
"keypress change".split(" ").forEach((eventName) => textarea.addEventListener(eventName, callPreview));