Связывание событий с динамически создаваемыми элементами и передачей параметров - PullRequest
1 голос
/ 08 января 2012

Я нашел похожие вопросы, когда искал решение для своей проблемы, но не думаю, что это именно то, что я ищу.

Использование .on () в jQuery не представляет сложности для связывания событий с динамически создаваемыми элементами, но я застрял при попытке передать разные параметры для вызова разных функций. После прочтения https://developer.mozilla.org/en/JavaScript/Guide/Closures я пришел к следующему рабочему примеру, но я хотел бы знать, является ли это лучшим способом сделать это или есть более элегантное решение?

http://jsfiddle.net/V25Zc/

Кроме того, я часто читаю, что использование eval () не рекомендуется из-за проблем с уязвимостью, но есть ли другой способ создания динамических имен функций?

Edit:

Большое спасибо всем за отличные ответы! Был ли удален один из ответов? Мне понравилось это из-за подсказки, чтобы сохранить параметр в атрибуте. Еще раз спасибо всем!

Ответы [ 5 ]

3 голосов
/ 08 января 2012

Смысл делегирования события заключается в том, что вам не нужно привязывать событие к каждому отдельному элементу (или к одному и тому же элементу несколько раз), только один раз к общему родителю, например, так:

function createLinks() {

    var $container = $("#container"),
        links = "";



    for (var i=0; i < 4; i++) {
        links += '<a class="linklink" href="#">Link_' + i + '</a>';
    }

    $container.html(links).on( "click", ".linklink", function(){
        console.log( "fn action"+$(this).index());
    });
}

createLinks();

Чтобы избежать использования eval, вы можете иметь массив функций и вызывать их по индексу:

arrayOfFunctions[ $(this).index() ]();

http://jsfiddle.net/V25Zc/2/

2 голосов
/ 08 января 2012

Если каждая функция действия на самом деле должна быть отдельной функцией (а не одной функцией, которая действует по-разному в зависимости от переданного ей индекса), то я бы сделал это таким образом, поместив атрибут в ссылку и извлекая его пощелкните мышью, чтобы увидеть, как это работает здесь: http://jsfiddle.net/jfriend00/gFmvG/.

function action0(){ console.log("fn action0"); }
function action1(){ console.log("fn action1"); }
function action2(){ console.log("fn action2"); }
function action3(){ console.log("fn action3"); }

var actions = [action0, action1, action2, action3];

function createLinks() {

    var $container = $("#container"),
        links = "";

    for (var i=0; i < 4; i++) {
        links += '<a id="link_' + i + '" href="#" data-num="' + i + '">Link_' + i + '</a>';
        $container.on("click", '"#link_' + i + '"', function() {
            actions[$(this).data("num")]();
        });
    }

    $container.html(links);
}

createLinks();

Если вам не нужно иметь отдельные функции для каждого действия, я бы сделал это так, как вы можете видеть здесь: http://jsfiddle.net/jfriend00/Z8Rq6/.

function doAction(index) {
    console.log("fn action" + index);
}

function createLinks() {

    var $container = $("#container"),
        links = "";

    for (var i=0; i < 4; i++) {
        links += '<a id="link_' + i + '" href="#" data-num="' + i + '">Link_' + i + '</a>';
        $container.on("click", '"#link_' + i + '"', function() {
            doAction($(this).data("num"));
        });
    }

    $container.html(links);
}

createLinks();

Это также можно сделать с помощью выполняемого замыкания, которое фиксирует значение индекса, но я считаю, что этот синтаксис несколько менее читабелен (требуется слишком много циклов разума, чтобы прочитать код и узнать, что он делает) поэтому я предпочитаю этот способ с атрибутом.

1 голос
/ 08 января 2012

Поместите свои функции в объект

var myFuncs = {
action0:function(){ console.log("fn action0"); },
action1:function(){ console.log("fn action1"); },
action2:function(){ console.log("fn action2"); },
action3:function(){ console.log("fn action3"); }
};

var funcNumber = "3";

for (var i=0; i < 4; i++) 
{
    links += '<a id="link_' + i + '" href="#">Link_' + i + '</a>';
    (function(myI)
    {
         $container.on("click", '"#link_' + i + '"', function()
         {
              myfuncs["action"+funcNumber](mI);
         });
    })(i);
}

Конечно, если они выполняются в глобальной области видимости, вы также можете сделать

for (var i=0; i < 4; i++) 
{
    links += '<a id="link_' + i + '" href="#">Link_' + i + '</a>';
    (function(myI)
    {
         $container.on("click", '"#link_' + i + '"', function()
         {
              window["action"+funcNumber](mI);
         });
    })(i);
}
1 голос
/ 08 января 2012

Похоже, ваша первоначальная проблема заключалась в том, что вы хотели вызвать функцию, имя которой будет определяться передаваемым параметром. Являются ли все эти функции глобальными по объему? Если это так, я бы просто сделал это:

function helpCallback(index) {
    return function() {
        window['action' + index]();
    }
}

Это имеет дополнительное преимущество, заключающееся в том, что, если вы когда-либо хотели передать аргументы в actionX, вы делаете это, передавая эти аргументы после индекса со следующей модификацией

function helpCallback(index) {
    var args = arguments;
    return function() {
        window['action' + index].apply(null, [].slice.call(args, 1));
    }
}

Так что helpCallback(1, "foo"); вернет функцию, которая вызывает action1('foo')

0 голосов
/ 08 января 2012

Я бы не стал создавать идентификаторы и ссылаться на них. Почему бы не использовать замыкания в привязках к фактическим элементам, которые вы создали.

Например, вы можете сделать что-то вроде

function createLinks() {

    var $container = $("#container");

    for (var i=0; i < 4; i++) {
        var link = $('<a href="#link' + i + '">Link_' + i + '</a>');
        $container.append(link);
        (function(){
            var index = i;
            link.click(function(){
                alert("Do my thing " + index);
            });
        })();
    }

}

createLinks();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...