Обработчик событий Javascript с параметрами


89

Я хочу создать eventHandler, который передает событие и некоторые параметры. Проблема в том, что функция не получает элемент. Вот пример:

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 должен быть определен вне анонимной функции. Как я могу использовать переданный элемент в анонимной функции? Есть ли способ сделать это?

А что насчет addEventListener? Кажется, я вообще не могу передать событие через addEventListener, не так ли?

Обновить

Кажется, я решил проблему с этим

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

Где это содержит this.element, к которому я могу получить доступ в функции.

AddEventListener

Но меня интересует addEventListener:

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

2
У вас есть элемент, элементы, элемент, задействованный в вашем вопросе. Можете ли вы быть менее запутанным?
mihai 03

Извините, я пытался привести пример своей ситуации, но это не помогло, я обновил код.
sebas2day

Вы бы искали e.target/ e.currentTarget?
Рольф

1
как отправить параметр, если я использую это: ok.addEventListener («щелкните», this.changeText.bind (this));
Альберто Акуна

Ответы:


103

Я не совсем понимаю, что пытается сделать ваш код, но вы можете сделать переменные доступными в любом обработчике событий, используя преимущества закрытия функций:

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

В зависимости от конкретной ситуации с кодированием вы почти всегда можете сделать какое-то закрытие, чтобы сохранить доступ к переменным для вас.

Из ваших комментариев, если вы пытаетесь достичь следующего:

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

Затем вы можете сделать это с помощью самоисполняющейся функции (IIFE), которая фиксирует нужные аргументы в закрытии по мере его выполнения и возвращает фактическую функцию обработчика событий:

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

Для получения дополнительной информации о том, как работает IIFE, см. Другие ссылки:

Код оболочки Javascript внутри анонимной функции

Выражение немедленно вызываемой функции (IIFE) в JavaScript - передача jQuery

Каковы хорошие варианты использования самоисполняющихся анонимных функций JavaScript?

В этой последней версии, возможно, легче увидеть, что она делает следующим образом:

// 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()для добавления аргументов в обратный вызов. Любые аргументы, которые вы передадите, .bind()будут добавлены к аргументам, которые будет иметь сам обратный вызов. Итак, вы могли сделать это:

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));

да, это почти то, что я пытаюсь сделать, но что, если анонимная функция будет передана как параметр с помощью addClickHandler, и вы хотите передать этой функции некоторые параметры с событием, например: element.addEventListener ('click', func (event, this.elements [i]));
sebas2day

5
@ sebas2day - Вы не можете этого сделать element.addEventListener('click', func(event, this.elements[i])). Javascript так не работает. Есть и другие способы обойти это, используя замыкания, но вы не можете сделать это так, как написали. addEventListener вызывает его обратный вызов только с одним аргументом (событием), и вы не можете его изменить.
jfriend00 03

Я добавил еще один пример того, как это сделать, в конец своего ответа.
jfriend00 03

@ jfriend00 Что вы могли бы сделать, так это использовать метод привязки. 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])) Обратите внимание, что аргумент события всегда стоит последним в аргументах функции и не объявляется явно в методе привязки.
Knight Yoshi

2
@ Bosh19 - посмотрите, что я добавил в конец своего ответа, чтобы объяснить конструкцию, о которой вы спрашивали. Это выражение немедленно вызываемой функции (IIFE), которое по сути является анонимно объявленной функцией, которая немедленно выполняется. Это ярлык для определения функции и ее последующего вызова - полезно, когда вы хотите, чтобы тело было встроено, и оно не будет вызываться где-либо еще, поэтому ему не нужно имя.
jfriend00

28

Это старый вопрос, но частый. Итак, позвольте мне добавить сюда это.

С синтаксисом стрелочной функции вы можете сделать это более лаконично, поскольку он лексически связан и может быть связан.

Выражение стрелочной функции является синтаксически компактной альтернативой регулярному функциональному выражению, хотя и без собственных привязок к ключевым словам this, arguments, super или new.target.

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

Если вам нужно очистить прослушиватель событий:

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

Вот сумасшедший однострочник:

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

Более послушная версия : больше подходит для любой разумной работы.

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

2
Это кажется разумным решением, но как насчет того, чтобы удалить тот же прослушиватель событий?
Dushyant Sabharwal

@SnnSnn: +1. Я использовал это, чтобы предоставить свойство класса обработчику событий. Я просто прошел, thisи обработчик получил доступ к тому, что ему нужно.
Роботрон

Если я правильно понимаю, вы на самом деле передаете анонимную функцию в качестве обработчика событий: (e) => {....}, а не yourEventHandlerFunction (). Это вызовет проблемы, если вы захотите удалить обработчик событий позже, поскольку вы передали анонимную функцию для начала с ???
PowerAktar

Ответ четко объясняет, как удалить прослушиватель событий, так что проблем нет.
snnsnn

9

Вы можете попробовать использовать метод привязки, я думаю, это достигает того, о чем вы просили. По крайней мере, это все еще очень полезно.

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

Учитывая обновление исходного вопроса, похоже, что возникла проблема с контекстом ("this") при передаче обработчиков событий. Основы объясняются, например, здесь http://www.w3schools.com/js/js_function_invocation.asp

Простая рабочая версия вашего примера могла бы читать

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);

См. Также Javascript call () и apply () vs bind ()?


2

Короткий ответ:

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

... 

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

Это не работает правильно. Если значение ваших параметров изменяется каждый раз, когда устанавливается обработчик событий, это приведет к неожиданным результатам, поскольку оно не превышает значение param1или param2. Если эти значения изменятся, они не будут установлены на значение, которое они были в то время, когда был создан обработчик событий. Им будет присвоено только текущее значение. Кроме того, это ничем не отличается от установки переменной вне области действия функции прослушивателя событий и ссылки на эту переменную в обработчике событий, поэтому она вообще не выполняет передачу параметров.
TetraDev

Я не совсем понял вашу точку зрения, поэтому мой ответ может быть неверным. Во всяком случае, обработчик события устанавливается один раз (не всегда, я думаю, но обычно это то, что кто-то хочет). Во-вторых, это в значительной степени говорит о том, что функция-обработчик - это myfunction, и что она имеет 2 параметра плюс переменную «событие». В-третьих, да, это работает, и результаты точно такие, как ожидалось.
user3093134

Нет, это не работает. Я протестировал его точно так же, как и вы, и моя точка зрения остается в силе. Если param1это noodleпервый раз , когда addEventListener называется, и второй раз , когда вы называете, paramэто cheeseто , когда слушатель события clickпожаров, param1будут установлены cheeseи не noodle. Следовательно, он не использует «замыкание» для запоминания значения, существовавшего на момент добавления прослушивателя событий. Существуют сценарии, в которых прослушиватель событий должен быть добавлен несколько раз, что не нужно иллюстрировать, чтобы моя точка зрения была верной.
TetraDev

Я не эксперт и раньше не слышал о «закрытии» в программировании, поэтому я не понимаю, что вы имеете в виду.
user3093134

1
Спасибо, что заглянули, я обязательно буду посещать ссылки, которые вы разместили. Кроме того, я должен сказать, что вы очень вежливы и честны, сэр, продолжайте в том же
духе

0

thisвнутри doThingsнаходится оконный объект. Попробуйте вместо этого:

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

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

    return {
        eventHandler: eventHandler
    };
};

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.