带参数的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传递事件吗?

更新资料

我似乎用'this'解决了问题

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 2012年

抱歉,我正在尝试举一个例子说明我的情况,但是进展不顺利,我更新了代码。
sebas2day 2012年

您要寻找e.target/e.currentTarget吗?
罗尔夫(Rolf)2015年

1
如果我使用this时如何发送参数:ok.addEventListener(“ click”,this.changeText.bind(this));
AlbertoAcuña'16

Answers:


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包装代码

JavaScript中立即调用的函数表达式(IIFE)-传递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 2012年

5
@ sebas2day-您不能这样做element.addEventListener('click', func(event, this.elements[i]))。Javascript不能那样工作。还有其他方法可以使用闭包,但是您不能以编写的方式来做。addEventListener仅使用一个参数(事件)来调用它的回调,并且您无法以任何方式更改它。
jfriend00 2012年

我在回答的末尾添加了另一个执行此操作的示例。
jfriend00 2012年

@ jfriend00您可以做的是使用bind方法。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])) 请注意,事件参数始终在函数的参数中位于最后,并且在bind方法中未明确声明。

2
@ Bosh19-看看我在回答的末尾添加了什么,以解释您所询问的构造。它是立即调用的函数表达式(IIFE),本质上是立即执行的匿名声明的函数。这是定义函数然后调用它的快捷方式-当您希望内联主体时很有用,并且不会在其他任何地方调用它,因此不需要名称。
jfriend00 2015年

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处理程序可以访问它所需的内容。
Robotron

如果我的理解是正确的,那么实际上您将传递一个匿名函数作为事件处理程序:(e)=> {....},而不是yourEventHandlerFunction()。如果您希望以后删除事件处理程序,则会导致问题,因为您传入的匿名函数的开头是???
PowerAktar

答案清楚地说明了如何删除事件侦听器,因此没有问题。
snnsnn

9

您可以尝试使用bind方法,这可以实现您所要求的。如果没有别的,它仍然非常有用。

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个参数以及“ event”变量。第三,是的,它确实起作用,并且结果完全符合预期。
user3093134

不,它不起作用。我完全按照您的方式进行了测试,但我的观点仍然有效。如果 param1noodle第一次使用addEventListener被调用,你怎么称呼它,第二次paramcheese那么每当事件监听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
    };
};

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.