20

我正在编写一个普通的 JavaScript工具,当启用它时,它会为传递给它的每个元素添加事件侦听器。

我想做这样的事情:

var do_something = function (obj) {
        // do something
    };

for (var i = 0; i < arr.length; i++) {
    arr[i].el.addEventListener('click', do_something(arr[i]));
}

不幸的是,这不起作用,因为据我所知,在添加事件侦听器时,参数只能传递给匿名函数

for (var i = 0; i < arr.length; i++) {
    arr[i].el.addEventListener('click', function (arr[i]) {
        // do something
    });
}

问题是我需要能够在禁用该工具时删除事件侦听器,但我认为不可能使用匿名函数删除事件侦听器

for (var i = 0; i < arr.length; i++) {
    arr[i].el.removeEventListener('click', do_something);
}

我知道我可以很容易地使用 jQuery 来解决我的问题,但我正在尝试最小化依赖关系。jQuery 必须以某种方式解决这个问题,但代码有点像丛林!

4

5 回答 5

21

这是无效的:

arr[i].el.addEventListener('click', do_something(arr[i]));

侦听器必须是函数引用。当您调用函数作为 的参数时addEventListener,函数的返回值将被视为事件处理程序。您不能在分配侦听器时指定参数。处理程序函数将始终以event作为第一个参数传递的方式调用。要传递其他参数,您可以将处理程序包装到匿名事件侦听器函数中,如下所示:

elem.addEventListener('click', function(event) {
  do_something( ... )
}

为了能够通过removeEventListener您删除处理程序函数:

function myListener(event) {
  do_something( ... );
}

elem.addEventListener('click', myListener);

// ...

elem.removeEventListener('click', myListener);

要访问处理函数中的其他变量,您可以使用闭包。例如:

function someFunc() {
  var a = 1,
      b = 2;

  function myListener(event) {
    do_something(a, b);
  }
  
  elem.addEventListener('click', myListener);
}
于 2013-02-26T11:39:16.403 回答
2

可以使用将参数传递给事件处理程序bind,也可以使用返回函数的处理程序

// using bind
var do_something = function (obj) {
  // do something
}

for (var i = 0; i < arr.length; i++) {
  arr[i].el.addEventListener('click', do_something.bind(this, arr[i]))
}


// using returning function
var do_something = obj => e {
  // do something
}

for (var i = 0; i < arr.length; i++) {
  arr[i].el.addEventListener('click', do_something(arr[i]))
}

但是在这两种情况下,删除事件处理程序是不可能的,因为bind会给出一个新的引用函数,并且每次执行 for 循环时返回函数也会返回一个新函数。

为了处理这个问题,我们需要将函数的引用存储在 an 中Array并从中删除。

// using bind
var do_something = function (obj) {
  // do something
}
var handlers = []

for (var i = 0; i < arr.length; i++) {
  const wrappedFunc = do_something.bind(this, arr[i])
  handlers.push(wrappedFunc)
  arr[i].el.addEventListener('click', wrappedFunc);
}
//removing handlers
function removeHandlers() {
  for (var i = 0; i < arr.length; i++) {
    arr[i].el.removeEventListener('click', handlers[i]);
  }
  handlers = []
}
于 2013-02-26T11:41:42.267 回答
0

这可以很容易地完成,只是不像你现在拥有的那样。

您需要添加或删除处理其他函数执行的函数,而不是尝试添加和删除随机匿名函数。

var
    // Here we are going to save references to our events to execute
    cache = {},

    // Create a unique string to mark our elements with
    expando = String( Math.random() ).split( '.' )[ 1 ],

    // Global unique ID; we use this to keep track of what events to fire on what elements
    guid = 1,

    // The function to add or remove. We use this to handler all of other 
    handler = function ( event ) {

        // Grab the list of functions to fire
        var handlers = ( cache[ this[ expando ] ] && cache[ this[ expando ] ][ event.type ] ) || false;

        // Make sure the list of functions we have is valid
        if ( !handlers || !handlers.length ) {
            return;
        }

        // Iterate over our individual handlers and call them as we go. Make sure we remeber to pass in the event Object
        handlers.forEach( function ( handler ) {
            handler.call( this, event );
        });

    },

    // If we want to add an event to an element, we use this function
    add = function ( element, type, fn ) {

        // We test if an element already has a guid assigned
        if ( !element[ expando ] ) {
            element[ expando ] = guid++;
        }

        // Grab the guid number
        var id = element[ expando ];

        // Make sure the element exists in our global cache
        cache[ id ] = cache[ id ] || {};

        // Grab the Array that we are going to store our handles in
        var handlers = cache[id ][ type ] = cache[ id ][ type ] || [];

       // Make sure the handle that was passed in is actually a function
        if ( typeof fn === 'function' ) {
            handlers.push( fn );
        }

        // Bind our master handler function to the element
        element.addEventListener( type, handler, false );

    };

// Add a click event to the body element
add( document.body, 'click', function ( event ) {
    console.log( 1 );
});

这只是我之前写的内容的缩减版,但我希望你能得到它的要点。

于 2013-02-26T12:08:25.453 回答
0

也许它不是完美的解决方案,但接近理想,此外我没有看到其他方法

感谢科斯塔斯·巴里奥蒂斯

这里的解决方案关键是:

那么,当我们需要在运行时的某个时刻移除附加的事件处理程序时,我们该怎么办?遇到 handleEvent,这是 JavaScript 在尝试查找已附加到事件的处理程序时查找的默认函数。

在 cas 链接被破坏(我放置第一种方式)

let Button = function () {

  this.el = document.createElement('button');
  this.addEvents();
}

Button.prototype.addEvents = function () {
  this.el.addEventListener('click', this);
}

Button.prototype.removeEvents = function () {
  this.el.removeEventListener('click', this);
}

Button.prototype.handleEvent = function (e) {
  switch(e.type) {
    case 'click': {
     this.clickHandler(e);
    }
  }
}

Button.prototype.clickHandler = function () {
  /* do something with this */
}

PS:

JS 类实现中的相同技术。

如果您使用 typescript 开发,则必须从 EventListenerObject 接口实现 handleEvent 方法

于 2022-02-19T07:32:37.513 回答
-2

要 ' addEventListener' 带有一些参数,可以使用以下代码:

{
   myButton.addEventListener("click",myFunction.bind(null,event,myParameter1,myParameter2)); 
}

函数“ myFunction”应该是这样的:

{
   function myFunction(event, para1, para2){...}
}
于 2019-04-21T04:35:42.723 回答