JavaScript事件处理程序:执行带参数处理程序的问题

3
我有这个问题:
我定义了一个需要参数的事件处理程序。
var handler = function(p1, p2){
    //some code
}

然后我在函数内部将事件处理程序添加到一个对象中。

function foo(p1, p2){
    //Some code
    obj.addEventListener('click', handler(p1, p2), false)
}

正如您已经知道的那样,上面的代码是不正确的。它不会监听事件。相反,它将立即执行该函数。现在要解决这个问题,我只需删除 handler(p1, p2) 并替换为 function(){ handler(p1, p2) }。但问题是我还有另一个函数要删除事件监听器,这种方法就行不通了。

function koo(){
    //Some code
    obj.removeEventListener('click', handler, false)
}

我该如何修复这个问题?


你是为一个元素还是多个元素做这个?fookoo在哪个作用域中?koo如何知道要移除哪个处理程序? - Felix Kling
抱歉回复晚了,我正在为几个元素进行操作,而且foo和koo是在全局范围内定义的,不是在任何其他函数内部定义的,如果我理解你的意思正确的话。还有一些其他函数除了koo之外,也会移除事件处理程序。 - einstein
3个回答

2

我认为你不想在那里传递参数 - 因为它是一个回调函数,你无法确定这些变量是什么。

你能做到吗...

(function() {

   var p1 = 'a',
       p2 = 'b',
       obj = document.getElementById('my-object');

   var handleClick = function(event) {
      // Access to p1 and p2
      // Access to `event` object containing info about the event
   }

   obj.addEventListener('click', handleClick, false);

   // If you want to remove it
   obj.removeEventListener('click', handleClick, false);

})();

请问为什么您希望在这个问题上争论呢?您是否还打算以非点击触发的方式调用它?


请问您能解释一下(function(){ //some code }()的作用吗?我以前从未见过这种写法。另外,您是不是忘记在结尾加上')'了? - einstein
是的,我忘记了当你进行函数声明时,变量提升不起作用。谢谢你唤醒我的记忆。 - alex
@Alex:我不知道函数foo和koo在你的代码中是什么意思?p1和p2也一直在变化,它们非常动态。而且是函数foo将参数传递给处理程序。在你的代码中,p1和p2更像是变量而不是参数吗? - einstein
@Alex: 我不明白在有 (function{})() 和根本没有它之间的区别?如果你说它立即执行,那么不加上 (function{})() 它不也会被执行吗? - einstein
@Alex:现在我明白你误解了我的意思。你认为foo和koo的唯一目的是删除和添加事件侦听器。它们还有其他功能,并且需要在私有范围之外进行访问,处理程序也是如此。 - einstein
显示剩余7条评论

2
我认为你需要创建一个闭包:
var createHandler = function(p1, p2){
    return function (event) {
        //some code that uses p1 and p2
    };
};

var handler;

现在,您可以像这样分配处理程序,同时仍然可以访问p1和p2:

function foo(p1, p2){
    handler = createHandler(p1, p2);
    //Some code
    obj.addEventListener('click', handler, false);
}

function koo(){
    //Some code
    obj.removeEventListener('click', handler, false);
    handler = null;
}

请注意,handler现在是一个全局变量。
更新:我刚意识到,在您的情况下,可以通过以下方式合并createHandlerfoo来简化此过程:
var handler; // we need this to be accessible both to foo and koo

function foo(p1, p2){
    handler = function(event) {
        // some code that uses p1 and p2
    };
    //Some code
    obj.addEventListener('click', handler, false);
}

function koo(){
    //Some code
    obj.removeEventListener('click', handler, false);
    handler = null;
}

我现在已经测试过了。问题是var handler = createHandler(p1, p2);必须在函数foo内定义才能工作。在外面不起作用。但如果它不在外面,我就无法删除事件侦听器,所以同样的问题。 - einstein
然后将 var handler; 放在 foo 函数外面(从而创建一个全局变量)。我已经更新了答案。 - Martijn
没问题(谢谢你的声望点数;-))。顺便说一下,我刚意识到它可以简化一下,看看更新后的答案。 - Martijn
@Woho87:这对你有用吗?这是我提出问题的原因:如果你总是在调用foo之后调用koo,那么它可以正常工作。但是一旦你调用两次foo,你就会失去对先前创建的处理程序的引用,此时就无法删除它了。目前的代码只支持创建和删除一个处理程序... - Felix Kling

1

这不就是吗:

function foo(){
    //Some code
    obj.addEventListener('click', handler, false)
}

传递函数而不是调用它。


澄清一下:当您将监听器设置为handler(p1, p2)时,您正在使用两个参数(p1p2)调用handler并将其返回的值分配给事件,而不是将函数handler作为监听器分配,这显然是您的意图。 - Alec Gorge
那只会传递一个 event 参数,不是 p1p2 吗? jsFiddle - alex
1
参数怎么办?p1和p2也需要传递,这就是问题所在。 - einstein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接