JavaScript中将元素作为事件处理程序的第一个参数传递的最简单方法是什么?

5

我知道在事件处理函数中将this的值更改为接收事件的元素非常有用。但是,我希望我的函数始终在我的应用程序上下文中调用,而不是在元素上下文中调用。这样,我就可以将它们用作事件处理程序以及在其他方式中使用,例如在setTimeout调用中。

因此,像这样的代码:

window.app = (function () {
    var that = {
        millerTime: function () {},
        changeEl: function (el) {
            el = el || this;
            // rest of code...
            that.millerTime();
        }
    };
    return that;
}());

可以简单地像这样:
window.app = (function () {
    return {
        millerTime: function () {},
        changeEl: function (el) {
            // rest of code...
            this.millerTime();
        }
    };
}());

第一种方法对我来说看起来很混乱。是否有一个好的简单方法将接收事件的元素作为第一个参数(最好是一个jQuery包装的元素)传递给我的事件处理函数,并在app的上下文中调用?假设我使用jQuery绑定了一堆事件处理程序,我不想一直包含匿名函数:

$('body').on('click', function (event) {
    app.changeEl.call(app, $(this), event);  // would be nice to get event too
});

我需要一个函数来处理这一切。目前我觉得没有办法避免传递匿名函数,但我想看看是否有人有解决方案。
我的尝试:
function overrideContext (event, fn) {
   if (!(this instanceof HTMLElement) ||
         typeof event === 'undefined'
   ) {
       return overrideContext;
   }

   // at this point we know jQuery called this function // ??
   var el = $(this);

   fn.call(app, el, event);
}

$('body').on('click', overrideContext(undefined, app.changeEl));
编辑: 我正在使用Function.prototype.bind(这是我不熟悉的),但仍然无法获取元素:
window.app = (function () {
    return {
         millerTime: function () {},
         changeEl: function (el) {
            // rest of code...
            console.log(this); // app
            this.millerTime();
         }
    };
}());

function overrideContext (evt, fn) {
    var el = $(this); // $(Window)
    console.log(arguments); // [undefined, app.changeEl, p.Event] 
    fn.call(app, el, event);
}

$('body').on('click', overrideContext.bind(null, undefined, app.changeEl));

使用 $('body').on('click', overrideContext.bind(app.changeEl)); 取代原来的方式,this 指向了 app.changeEl 函数,并且参数长度为1,仅包含 p.Event。但是在任何一种情况下我仍然无法获取元素。


1
查看 $.proxy http://api.jquery.com/jQuery.proxy/,它允许您更改处理程序的上下文。 - charlietfl
通过查看http://api.jquery.com/jQuery.proxy/,`$.proxy`似乎不允许传入元素。我需要一种类似的延迟绑定方式。我想同时占有蛋糕和吃掉它。 - danronmoon
谷歌一些用例演示/教程...可以做得比你想象的更多。 - charlietfl
2个回答

3
你可以使用 Function.prototype.bind
$('body').on('click', overrideContext.bind(null, undefined, app.changeEl));

您可以将实际的元素作为该方法的上下文进行传递。
$('body').on('click', overrideContext.bind(app.changeEl));

好的,我对 Function.prototype.bind 还不熟悉,我认为在事件处理程序上学习如何使用它是一个可怕的介绍。无论您使用哪种语句,我仍然无法将单击的元素放入参数中。我已经编辑了我的问题并附上了结果。 - danronmoon

0

我认为你的错误在于试图控制将哪些参数传递给事件处理程序。如果你真的非常想要这样做,你就必须创建自己的事件处理工具,就像jQuery一样,并手动调用处理程序,传递任何你想要的参数。

但是,你真的需要那么做吗?如果你依赖于使用addEventListener附加的常规处理程序,或者使用jQuery中提供的各种方法附加的处理程序,你将始终获得event对象作为第一个参数。而触发事件的元素将始终可用于event.target

考虑到这一点,你可以像jAndy建议的那样使用Function.prototype.bind,将this设置为任何你想要的值。


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