77

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

这是原始代码:

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

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

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

4

15 回答 15

177

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

ES6

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

ES5

['click','ontouchstart'].forEach( function(evt) {
    element.addEventListener(evt, dosomething, false);
});
于 2017-03-25T20:00:27.963 回答
30

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

// 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>

于 2012-08-07T12:43:31.517 回答
24

您可以定义一个函数并传递它。匿名函数在任何方面都不特殊,所有函数都可以作为值传递。

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

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

function handler(event) {
    do_something();
}
于 2012-08-07T12:13:03.177 回答
12

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

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))
于 2012-08-07T12:17:12.517 回答
9

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

var first = document.getElementById('first');
first.addEventListener('touchstart', do_something, false);
first.addEventListener('click', do_something, false);
于 2012-08-07T12:13:58.187 回答
3

对我来说最简单的解决方案是将代码传递到一个单独的函数中,然后在事件侦听器中调用该函数,就像一个魅力。

function somefunction() { ..code goes here ..}

variable.addEventListener('keyup', function() {
   somefunction(); // calling function on keyup event
})

variable.addEventListener('keydown', function() {
   somefunction(); //calling function on keydown event
})
于 2019-03-14T08:16:55.843 回答
2

我有一个附加到原型的小解决方案

  EventTarget.prototype.addEventListeners = function(type, listener, options,extra) {
  let arr = type;
  if(typeof type == 'string'){
    let sp = type.split(/[\s,;]+/);
    arr = sp;   
  }
  for(let a of arr){
    this.addEventListener(a,listener,options,extra);
  }
};

允许你给它一个字符串或数组。字符串可以用空格('')、逗号(',')或分号(';')分隔

于 2018-09-21T06:19:53.933 回答
1

document.getElementById('first').addEventListener('touchstart',myFunction);

document.getElementById('first').addEventListener('click',myFunction);
    
function myFunction(e){
  e.preventDefault();e.stopPropagation()
  do_something();
}    

您应该使用e.stopPropagation(),因为如果没有,您的函数将在移动设备上触发两次

于 2018-06-09T21:39:44.897 回答
1

我刚刚做了这个功能(故意缩小):

((i,e,f)=>e.forEach(o=>i.addEventListener(o,f)))(element, events, handler)

用法:

((i,e,f)=>e.forEach(o=>i.addEventListener(o,f)))(element, ['click', 'touchstart'], (event) => {
    // function body
});

与其他方法相比的不同之处在于处理函数只定义一次,然后传递给 every addEventListener

编辑:

添加非缩小版本以使其更易于理解。缩小版仅用于复制粘贴和使用。

((element, event_names, handler) => {

    event_names.forEach( (event_name) => {
        element.addEventListener(event_name, handler)
    })

})(element, ['click', 'touchstart'], (event) => {

    // function body

});
于 2018-11-06T14:37:13.903 回答
1

像这样的东西怎么样:

['focusout','keydown'].forEach( function(evt) {
        self.slave.addEventListener(evt, function(event) {
            // Here `this` is for the slave, i.e. `self.slave`
            if ((event.type === 'keydown' && event.which === 27) || event.type === 'focusout') {
                this.style.display = 'none';
                this.parentNode.querySelector('.master').style.display = '';
                this.parentNode.querySelector('.master').value = this.value;
                console.log('out');
            }
        }, false);
});

// The above is replacement of:
 /*   self.slave.addEventListener("focusout", function(event) { })
      self.slave.addEventListener("keydown", function(event) {
         if (event.which === 27) {  // Esc
            }
      })
*/
于 2020-05-28T01:21:52.793 回答
0

半相关,但这是用于初始化每个元素特定的唯一事件侦听器。

您可以使用滑块实时显示值,或检查控制台。在<input>元素上,我有一个attr名为 的标签data-whatever,因此您可以根据需要自定义该数据。

sliders = document.querySelectorAll("input");
sliders.forEach(item=> {
  item.addEventListener('input', (e) => {
    console.log(`${item.getAttribute("data-whatever")} is this value: ${e.target.value}`);
    item.nextElementSibling.textContent = e.target.value;
  });
})
.wrapper {
  display: flex;
}
span {
  padding-right: 30px;
  margin-left: 5px;
}
* {
  font-size: 12px
}
<div class="wrapper">
  <input type="range" min="1" data-whatever="size" max="800" value="50" id="sliderSize">
  <em>50</em>
  <span>Size</span>
  <br>
  <input type="range" min="1" data-whatever="OriginY" max="800" value="50" id="sliderOriginY">
  <em>50</em>
  <span>OriginY</span>
  <br>
  <input type="range" min="1" data-whatever="OriginX" max="800" value="50" id="sliderOriginX">
  <em>50</em>
  <span>OriginX</span>
</div>

于 2018-11-29T03:12:54.017 回答
0

这是我在工作流程中处理多个事件的解决方案。

let h2 = document.querySelector("h2");

function addMultipleEvents(eventsArray, targetElem, handler) {
        eventsArray.map(function(event) {
            targetElem.addEventListener(event, handler, false);
        }
    );
}
let counter = 0;
function countP() {
    counter++;
    h2.innerHTML = counter;
}

// magic starts over here...
addMultipleEvents(['click', 'mouseleave', 'mouseenter'], h2, countP);
<h1>MULTI EVENTS DEMO - If you click, move away or enter the mouse on the number, it counts...</h1>

<h2 style="text-align:center; font: bold 3em comic; cursor: pointer">0</h2>

于 2019-08-13T18:22:19.687 回答
0
//catch volume update
var volEvents = "change,input";
var volEventsArr = volEvents.split(",");
for(var i = 0;i<volknob.length;i++) {
    for(var k=0;k<volEventsArr.length;k++) {
    volknob[i].addEventListener(volEventsArr[k], function() {
        var cfa = document.getElementsByClassName('watch_televised');
        for (var j = 0; j<cfa.length; j++) {
            cfa[j].volume = this.value / 100;
        }
    });
}
}
于 2019-10-10T13:56:38.860 回答
0

你可以简单地迭代一个Object. 这可以与单个或多个元素一起使用。这是一个例子:

const ELEMENTS = {'click': element1, ...};
for (const [key, value] of Object.entries(ELEMENTS)) {
    value.addEventListener(key, () => {
        do_something();
    });
}

Whenkey是事件的类型,并且value是添加事件时的元素,因此您可以编辑ELEMENTS添加元素和事件的类型。

于 2021-09-14T15:18:30.253 回答
-1

这个迷你 javascript 库 (1.3 KB) 可以做所有这些事情

https://github.com/Norair1997/norjs/

nor.event(["#first"], ["touchstart", "click"], [doSomething, doSomething]);
于 2018-05-27T19:28:53.437 回答