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 ループが実行されるたびに新しい関数を返すためです。

この問題を処理するには、関数の参照を に保存し、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 に答える