ผูกหลายเหตุการณ์กับผู้ฟัง (โดยไม่มี JQuery)?


144

ในขณะที่ทำงานกับกิจกรรมของเบราว์เซอร์ฉันได้เริ่มรวมการทำงานของ touchEvents ของ Safari เข้ากับอุปกรณ์มือถือ ฉันพบว่าaddEventListeners กำลังซ้อนกับเงื่อนไข โครงการนี้ไม่สามารถใช้ JQuery

ผู้ฟังเหตุการณ์มาตรฐาน:

/* 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อนุญาตให้มีหลายเหตุการณ์เช่น:

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

มีวิธีการรวมสองฟังเหตุการณ์ในตัวอย่าง JQuery? อดีต:

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

ข้อเสนอแนะหรือคำแนะนำใด ๆ ที่ชื่นชม!


@RobG อาจเป็นเพราะคำถามนั้นถามถึงวิธีการทำซ้ำฟังก์ชั่นบางอย่างของ jQuery ฉันไม่แน่ใจว่าเป็นการใช้แท็กที่เหมาะสมหรือไม่
Michael Martin-Smucker

ยุติธรรมพอฉันแค่ดูเหมือนว่าคำถามไม่ต้องการมัน ดูค่อนข้างน่าสะอิดสะเอียนแม้ว่าถูกลบไปแล้ว
RobG

คำตอบ:


104

ใน POJS คุณเพิ่มผู้ฟังทีละคน ไม่ใช่เรื่องปกติที่จะเพิ่มผู้ฟังคนเดียวกันสำหรับสองเหตุการณ์ที่แตกต่างกันในองค์ประกอบเดียวกัน คุณสามารถเขียนฟังก์ชั่นเล็ก ๆ ของคุณเองเพื่อทำงานเช่น:

/* 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(){…});

หวังว่ามันจะแสดงแนวคิด

แก้ไข 2016-02-25

ความคิดเห็นของ Dalgard ทำให้ฉันทบทวนสิ่งนี้อีกครั้ง ฉันเดาว่าการเพิ่ม listener เดียวกันสำหรับเหตุการณ์หลาย ๆ อย่างบนองค์ประกอบเดียวนั้นเป็นเรื่องธรรมดามากขึ้นในขณะนี้เพื่อครอบคลุมประเภทอินเตอร์เฟสที่ใช้งานอยู่และคำตอบของ Isaac เสนอวิธีการใช้งานที่ดีในตัวเพื่อลดรหัส (แม้ว่ารหัสน้อยกว่า ไม่จำเป็นต้องเป็นโบนัส) ขยายด้วยฟังก์ชั่นลูกศร ECMAScript 2015 ให้:

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

กลยุทธ์ที่คล้ายกันสามารถเพิ่มผู้ฟังเดียวกันให้กับองค์ประกอบหลาย ๆ องค์ประกอบ แต่ความจำเป็นที่ต้องทำนั่นอาจเป็นตัวบ่งชี้สำหรับการมอบหมายเหตุการณ์


4
ขอขอบคุณสำหรับประโยคที่ว่า"It is not common to add the same listener for two different events on the same element."บางครั้ง (สีเขียว) devs ต้องการที่จะได้ยินนี้จะรู้ว่าพวกเขากำลังทำมันขวา :)
อีวานกล้า

1
คุณไม่หมายถึง "มันไม่ใช่เรื่องแปลก" หรือไม่?
dalgard

2
@ dalgard - เป็นเรื่องปกติมากขึ้นในขณะนี้ที่อุปกรณ์สัมผัสนั้นมีอยู่ทั่วไป แต่สำหรับเหตุการณ์จำนวน จำกัด เท่านั้น (เช่น mousemove และ touchmove) มันจำเป็นต้องแสดงสายตาสั้น ๆ ของการตั้งชื่อเหตุการณ์หลังจากรายการทางกายภาพย้ายตัวชี้อาจมีความเหมาะสมมากขึ้น มันสามารถนำมาใช้โดยการสัมผัสหรืออุปกรณ์อื่น ๆ ก่อนที่หนู (หรือเมาส์) มีล้อ x / y บางตัวที่ฉันเคยใช้มีล้อมือและเท้า (Stecometer 1970) นอกจากนี้ยังมีแทร็กบอลและสเฟียร์บางส่วนเคลื่อนไหวเป็น 3 มิติ
RobG

2
@RobG: API ที่ฉันติดต่อด้วยคือ DOM และใช่ข้อบกพร่องของมันคือพยุหเสนา :) แต่ก็อาจเป็นคำถามของการหลีกเลี่ยงรหัสที่ซ้ำกันในผู้ฟังที่คล้ายกัน
dalgard

1
@ PedroFerreira ใช่แน่นอนอาจจะมากกว่าครึ่งหนึ่งของเบราว์เซอร์ที่ใช้ในปัจจุบันไม่สนับสนุนลูกศรฟังก์ชั่น แต่พวกเขากำลังสนุกกับการเล่นกับและมีอยู่เสมอบาเบล ;-)
RobG

119

ไวยากรณ์ขนาดกะทัดรัดบางตัวที่ได้ผลลัพธ์ที่ต้องการคือ POJS:

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

154
หรือโดยตรง['mousemove', 'touchmove'].forEach(...)
Dan Dascalescu

+1 และไม่จำเป็นต้องมีส่วนขยาย« ECMAScript 2015 ฟังก์ชันลูกศร»! ;-)
Pedro Ferreira

@ zuckerburg เริ่มต้นด้วยแทนที่จะใส่รหัสที่คุณ hardcoded strning แล้วทำการแยกมันออกมาคุณแน่ใจหรือไม่ว่านี่เป็นวิธีที่จะไป? คุณแน่ใจหรือว่านี่เป็นวิธีที่เขียนได้ง่ายที่สุด ['mousemove', 'touchmove'].forEach(function(event) { window.addEventListener(event, handler);}); จะไม่เพียง แต่จะอ่านง่ายขึ้น แต่ยังเร็วกว่ามากโดยไม่ต้องแยกสตริงแล้วเรียกใช้ฟังก์ชันสำหรับแต่ละรายการในอาร์เรย์ผลลัพธ์
Iharob Al Asimi

2
@IharobAlAsimi รหัสนี้ถูกเขียนเมื่อ 4 ปีก่อนฉันพบสเปซบาร์ในเวลานั้น การแยกสตริงนั้นเกี่ยวข้องกับการใช้สตริงของ OP
Isaac

1
@IharobAlAsimi ฉันไม่ได้เขียนรหัส คุณบอกว่ามันอ่านไม่ได้ เห็นได้ชัดว่าไม่ใช่เพราะคุณและฉันต่างก็อ่านโค้ดได้ นี่มันเหมือนกับการถกเถียงเรื่องไวยากรณ์ 99% ของโปรแกรมเมอร์ทั้งหมดสามารถอ่านโค้ดได้ค่อนข้างดี
zuckerburg

55

ทำความสะอาดคำตอบของ Isaac:

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

แก้ไข

ฟังก์ชั่นผู้ช่วย ES6:

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

1
FYI: map! = forEach
jpoppe

10

สำหรับฉัน; รหัสนี้ใช้งานได้ดีและเป็นรหัสที่สั้นที่สุดในการจัดการหลายเหตุการณ์ด้วยฟังก์ชั่นเดียวกัน (แบบอินไลน์)

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.");
    });
}

สิ่งที่ฉันกำลังมองหา ขอบคุณ!
Elharony


3

ฉันมีทางออกที่ง่ายกว่าสำหรับคุณ:

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

ฉันได้ทดสอบสิ่งนี้มันใช้งานได้ดีในด้านบวกมันมีขนาดกะทัดรัดและไม่ซับซ้อนเหมือนตัวอย่างอื่น ๆ ที่นี่


1
มีเพียงหนึ่งไฟล์ที่เป็นไปได้เท่านั้น บางทีคุณอาจจะเขียนทับผู้ฟังเก่า สิ่งนี้อาจเป็นปัญหาได้ทั้งนี้ขึ้นอยู่กับสภาพแวดล้อมของคุณ
HolgerJeromin

1

addEventListenerใช้สตริงง่ายๆที่แสดงถึงevent.type ดังนั้นคุณต้องเขียนฟังก์ชั่นที่กำหนดเองเพื่อทำซ้ำหลาย ๆ เหตุการณ์

สิ่งนี้กำลังถูกจัดการใน jQuery โดยใช้. split ("") จากนั้นวนซ้ำรายการเพื่อตั้งค่า eventListeners สำหรับแต่ละ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

0

วิธีหนึ่งในการทำ:

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;
}
<div id="troll">
  <img src="http://images.mmorpg.com/features/7909/images/Troll.png" alt="Troll">
</div>

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.