Parametreli Javascript olay işleyicisi


92

Olayı ve bazı parametreleri geçiren bir eventHandler yapmak istiyorum. Sorun, işlevin öğeyi almamasıdır. İşte bir örnek:

doClick = function(func){
    var elem = .. // the element where it is all about
    elem.onclick = function(e){
        func(e, elem);
    }
}
doClick(function(e, element){
    // do stuff with element and the event
});

'Elem' anonim işlevin dışında tanımlanmalıdır. Anonim işlev içinde kullanılmak üzere iletilen öğeyi nasıl edinebilirim? Bunu yapmanın bir yolu var mı?

Peki addEventListener ne olacak? Olayı addEventListener aracılığıyla hiç geçiremiyorum, değil mi?

Güncelleme

Sorunu "bu" ile çözmüş gibiydim

doClick = function(func){
    var that = this;
    this.element.onclick = function(e){
        func(e, that);
    }
}

Bu öğenin bulunduğu yer, işlevde erişebileceğim.

AddEventListener

Ama addEventListener'ı merak ediyorum:

function doClick(elem, func){
    element.addEventListener('click', func(event, elem), false);
}

2
Sorunuzda elem, elementler, element var. Daha az kafa karıştırıcı olabilir misin?
mihai

Üzgünüm, durumuma bir örnek vermeye çalışıyordum ama bu pek iyi gitmedi, kodu güncelledim.
sebas2day

Aradığınız olabilir mi e.target/ ' e.currentTarget?
Rolf

1
bunu kullanıyorsam bir parametre nasıl gönderilir: ok.addEventListener ("click", this.changeText.bind (this));
Alberto Acuña

Yanıtlar:


103

Kodunuzun tam olarak ne yapmaya çalıştığını anlamıyorum, ancak işlev kapanışlarının avantajlarını kullanarak değişkenleri herhangi bir olay işleyicisinde kullanılabilir hale getirebilirsiniz:

function addClickHandler(elem, arg1, arg2) {
    elem.addEventListener('click', function(e) {
        // in the event handler function here, you can directly refer
        // to arg1 and arg2 from the parent function arguments
    }, false);
}

Kesin kodlama durumunuza bağlı olarak, değişkenlere erişimi korumak için hemen hemen her zaman bir çeşit kapatma yapabilirsiniz.

Yorumlarınıza göre, başarmaya çalıştığınız şey şuysa:

element.addEventListener('click', func(event, this.elements[i]))

Ardından, bunu gerçek olay işleyici işlevini çalıştırırken ve döndürürken bir kapanışta istediğiniz bağımsız değişkenleri yakalayan kendi kendine çalışan bir işlevle (IIFE) yapabilirsiniz:

element.addEventListener('click', (function(passedInElement) {
    return function(e) {func(e, passedInElement); };
}) (this.elements[i]), false);

Bir IIFE'nin nasıl çalıştığı hakkında daha fazla bilgi için şu diğer referanslara bakın:

Anonim işlevin içine kod sarma

JavaScript'te Hemen Çağrılan Fonksiyon İfadesi (IIFE) - jQuery'yi Geçirme

Anonim işlevleri kendi kendine çalıştıran JavaScript'in iyi kullanım örnekleri nelerdir?

Bu son sürüm, bunun ne yaptığını görmek belki daha kolay:

// return our event handler while capturing an argument in the closure
function handleEvent(passedInElement) {
    return function(e) {
        func(e, passedInElement); 
    };
}

element.addEventListener('click', handleEvent(this.elements[i]));

.bind()Geri aramaya argümanlar eklemek de mümkündür . .bind()İlettiğiniz herhangi bir bağımsız değişken, geri aramanın kendisinin sahip olacağı bağımsız değişkenlerin başına eklenecektir. Yani bunu yapabilirsin:

elem.addEventListener('click', function(a1, a2, e) {
    // inside the event handler, you have access to both your arguments
    // and the event object that the event handler passes
}.bind(elem, arg1, arg2));

evet neredeyse yapmaya çalıştığım şey bu, ama ya anonim işlev addClickHandler tarafından parametre olarak geçirilirse ve bu işleve şu gibi olayla bazı parametreler vermek isterseniz: element.addEventListener ('click', func (event, this.elements [i]));
sebas2day

5
@ sebas2day - Yapamazsın element.addEventListener('click', func(event, this.elements[i])). Javascript sadece bu şekilde çalışmıyor. Kapatmanın başka yolları da var, ancak bunu yazdığınız şekilde yapamazsınız. addEventListener, geri çağrısını tam olarak bir bağımsız değişkenle (olay) çağırır ve bunu hiçbir şekilde değiştiremezsiniz.
jfriend00

Cevabımın sonuna bunu yapmanın başka bir örneğini ekledim.
jfriend00

@ jfriend00 Yapabileceğiniz şey bağlama yöntemini kullanmaktır. function eventFunction (arg, evt) { console.log(arg[0],arg[1],arg[2]) console.log(evt) } var el = document.getElementById('elementID'); el.addEventListener('click', eventFunction.bind(el,[1,2,3])) Olay bağımsız değişkeninin, işlevin bağımsız değişkenlerinde her zaman en sonda olduğunu ve bağlama yönteminde açıkça bildirilmediğini unutmayın.
Knight Yoshi

2
@ Bosh19 - sorduğunuz yapıyı açıklamak için cevabımın sonuna ne eklediğime bakın. Bu, hemen çalıştırılan, esasen anonim olarak bildirilen bir işlev olan hemen çağrılan bir işlev ifadesidir (IIFE). Bu, bir işlevi tanımlamak ve sonra onu çağırmak için bir kısayol - gövdenin satır içi olmasını istediğinizde kullanışlıdır ve başka hiçbir yerde çağrılmayacağı için bir ada ihtiyaç duymaz.
jfriend00

29

Bu eski bir sorudur ama ortak bir sorudur. Öyleyse bunu buraya eklememe izin verin.

İle ok fonksiyonu sözdizimi , sözcüksel olarak bağlandığı ve zincirlenebildiği için bunu daha kısa ve öz bir şekilde elde edebilirsiniz.

Ok işlevi ifadesi, normal işlev ifadesine sözdizimsel olarak kompakt bir alternatiftir, ancak buna, argümanlara, süper veya new.target anahtar kelimelerine kendi bağları yoktur.

const event_handler = (event, arg) => console.log(event, arg);
el.addEventListener('click', (event) => event_handler(event, 'An argument'));

Olay dinleyicisini temizlemeniz gerekiyorsa:

// Let's use use good old function sytax
function event_handler(event, arg) {
  console.log(event, arg);
}

// Assign the listener callback to a variable
var doClick = (event) => event_handler(event, 'An argument'); 

el.addEventListener('click', doClick);

// Do some work...

// Then later in the code, clean up
el.removeEventListener('click', doClick);

İşte çılgın tek satırlık:

// You can replace console.log with some other callback function
el.addEventListener('click', (event) => ((arg) => console.log(event, arg))('An argument'));

Daha uysal versiyon : Herhangi bir aklı başında çalışma için daha uygun.

el.addEventListener('click', (event) => ((arg) => {
  console.log(event, arg);
})('An argument'));

2
Bu makul bir çözüm gibi görünüyor, ancak aynı olay dinleyicisini kaldırmanız gerektiğinde ne olacak?
Dushyant Sabharwal

@SnnSnn: +1. Bunu olay işleyicisine bir sınıf özelliği sağlamak için kullandım. İçeri geçtim thisve görevli ihtiyacı olan şeye erişebildi.
Robotron

1
Anladığım doğruysa, olay işleyiciniz olarak anonim bir işlevi iletiyor olacaksınız: (e) => {....}, yourEventHandlerFunction () değil. Başlamak için anonim bir işlevi aktardığınız için, olay işleyicisini daha sonra kaldırmak isterseniz bu sorunlara neden olacaktır.
PowerAktar

Cevap, olay dinleyicisinin nasıl kaldırılacağını açık bir şekilde açıklıyor, bu yüzden orada sorun yok.
snnsnn

9

Deneyebileceğiniz bir şey bağlama yöntemini kullanmaktır, bence bu, istediğiniz şeyi başarır. Hiçbir şey yoksa, yine de çok kullanışlıdır.

function doClick(elem, func) {
  var diffElem = document.getElementById('some_element'); //could be the same or different element than the element in the doClick argument
  diffElem.addEventListener('click', func.bind(diffElem, elem))
}

function clickEvent(elem, evt) {
  console.log(this);
  console.log(elem); 
  // 'this' and elem can be the same thing if the first parameter 
  // of the bind method is the element the event is being attached to from the argument passed to doClick
  console.log(evt);
}

var elem = document.getElementById('elem_to_do_stuff_with');
doClick(elem, clickEvent);

2

Orijinal soruya yapılan güncelleme göz önüne alındığında, olay işleyicileri geçerken bağlamla ilgili ("bu") sorun var gibi görünüyor. Temel bilgiler, örneğin burada açıklanmıştır http://www.w3schools.com/js/js_function_invocation.asp

Örneğinizin basit bir çalışma versiyonu okuyabilir

var doClick = function(event, additionalParameter){
    // do stuff with event and this being the triggering event and caller
}

element.addEventListener('click', function(event)
{
  var additionalParameter = ...;
  doClick.call(this, event, additionalParameter );
}, false);

Ayrıca bkz. Javascript call () & apply () vs bind ()?


1

Kısa cevap:

x.addEventListener("click", function(e){myfunction(e, param1, param2)});

... 

function myfunction(e, param1, param1) {
    ... 
} 

1
Bu doğru çalışmıyor. Parametrelerinizin değeri, olay işleyicisi her ayarlandığında değişirse, param1veya değerinin üzerinde kapanmayacağı için beklenmeyen sonuçlar üretecektir param2. Bu değerler değişirse, olay işleyicinin yaratıldığı sırada bulundukları değere ayarlanmayacaktır. Yalnızca mevcut değere ayarlanacaklar. Ayrıca, olay dinleyici işlevinin kapsamı dışındaki bir değişkeni ayarlamaktan ve olay işleyicide bu değişkeni referans almaktan farklı değildir, dolayısıyla parametrelerin aktarılmasını hiç başaramaz.
TetraDev

Ne demek istediğini gerçekten anlamadım, bu yüzden cevabım yanlış olabilir. Her neyse, olay işleyicisi bir kez ayarlanır (her zaman tahmin etmiyorum ama genellikle birinin istediği budur). İkinci olarak, bu hemen hemen işleyici işlevinin myfunction olduğunu ve 2 parametresi artı "olay" değişkenine sahip olduğunu söyler. Üçüncüsü, evet işe yarıyor ve sonuçlar tam olarak beklendiği gibi.
user3093134

1
Hayır, çalışmıyor. Tam olarak senin yaptığın gibi test ettim ve puanım geçerli. Eğer param1bir noodleaddEventListener denir ilk kez ve siz çağrı ikinci kez paramolan cheeseolay dinleyicisi her ardından clickyangınlar param1ayarlanır cheesedeğil noodle. Bu nedenle, olay dinleyicisinin eklendiği sırada var olan değeri hatırlamak için bir "kapanış" kullanmaz. Benim noktamın geçerli olması için gösterilmesi gerekmeyen olay dinleyicisinin birden çok kez eklenmesi gereken senaryolar vardır.
TetraDev

Ben bir uzman değilim ve daha önce programlamada "kapanış" ı duymadım, bu yüzden bununla ne demek istediğini anlamıyorum.
user3093134

2
Kontrol ettiğiniz için teşekkür ederiz, gönderdiğiniz bağlantıları da kesinlikle ziyaret edeceğim. Ayrıca, çok kibar ve dürüst olduğunuzu söylemeliyim efendim, devam edin ve iyi günler :)
user3093134

0

thisiçinde doThingspencere nesnesidir. Bunun yerine şunu deneyin:

var doThings = function (element) {
    var eventHandler = function(ev, func){
        if (element[ev] == undefined) {
            return;
        }

        element[ev] = function(e){
            func(e, element);
        }
    };

    return {
        eventHandler: eventHandler
    };
};

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.