Обробник подій 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
});

Елем повинен бути визначений поза анонімною функцією. Як я можу отримати переданий елемент для використання в анонімній функції? Чи є спосіб зробити це?

А як щодо 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

Вибачте, я намагався навести приклад своєї ситуації, але це не вдалося, я оновив код.
sebas2day,

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

1
як надіслати параметр, якщо im використовує це: 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

В кінці своєї відповіді я додав ще один приклад цього.
jfriend00

@ 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])) Зауважте, що аргумент події завжди є останнім в аргументах функції, і він явно не оголошується в методі прив'язки.
Лицар Йоші

2
@ Bosh19 - подивіться, що я додав у кінці моєї відповіді, щоб пояснити конструкцію, про яку ви запитували. Це негайно викликаний вираз функції (IIFE), який по суті є анонімно оголошеною функцією, яка негайно виконується. Це ярлик для визначення функції, а потім її виклику - корисно, коли ви хочете, щоб тіло було вбудованим, і воно більше ніде не буде викликане, тому йому не потрібно ім’я.
jfriend00

28

Це старе питання, але загальне. Тож дозвольте мені додати цю тут.

За допомогою синтаксису функції стрілки ви можете досягти його більш стислим способом, оскільки він лексично пов’язаний і може бути ланцюжком.

Вираз функції стрілки є синтаксично компактною альтернативою виразу регулярної функції, хоча і без власних прив'язок до ключових слів this, аргументи, 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

Враховуючи оновлення вихідного питання, здається, що виникають проблеми з контекстом ("це") під час передачі обробників подій. Основи пояснюються, наприклад, тут: http://www.w3schools.com/js/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 () & apply () проти bind ()?


2

Коротка відповідь:

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

... 

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

Це працює неправильно. Якщо значення ваших параметрів змінюється кожного разу, коли встановлюється обробник події, це дасть несподівані результати, оскільки воно не закривається за значенням param1або param2. Якщо ці значення зміняться, для них не буде встановлено значення, яке було на час створення обробника події. Їм буде встановлено лише поточне значення. Крім того, це нічим не відрізняється від встановлення змінної поза сферою дії функції прослуховування подій та посилання на цю змінну в обробнику подій, тому вона взагалі не виконує передачу параметрів.
TetraDev

Я насправді не зрозумів вашу думку, тому моя відповідь може бути вимкнена. У будь-якому випадку, обробник події встановлюється один раз (не завжди, напевно, але зазвичай це те, що хтось хоче). По-друге, це майже говорить про те, що функція обробника є моєю функцією і що вона має 2 параметри плюс змінну "event". По-третє, так, це працює, і результати точно такі, як очікувалося.
user3093134

Ні, це не працює. Я перевірив це точно так само, як і ви, і моя думка залишається в силі. Якщо param1це noodleперший раз , коли addEventListener називається, і другий раз , коли ви називаєте, paramце cheeseте , коли слухач події clickпожеж, param1будуть встановлені cheeseі не noodle. Тому він не використовує "закриття", щоб запам'ятати значення, яке існувало на момент додавання слухача події. Існують сценарії, коли прослуховувач подій потрібно додавати кілька разів, які не потрібно ілюструвати, щоб мій пункт був дійсним.
TetraDev

Я не фахівець і раніше не чув про "закриття" програмування, тому я не розумію, що ви маєте на увазі під цим.
user3093134

1
Дякуємо за перевірку, я також обов'язково відвідаю посилання, які ви розмістили. Крім того, я повинен сказати, що ви дуже ввічливий і чесний сер, так продовжуйте і хорошого дня :)
user3093134

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

-2
let obj = MyObject();

elem.someEvent( function(){ obj.func(param) } );

//calls the MyObject.func, passing the param.

param також може бути функцією зворотного виклику (у глобальному контексті -say-), тому може бути легко викликаний зворотним зв'язком із запитаними параметрами.
Δημήτρης Βουζουναράς
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.