Как добавить обработчик событий с аргументами в массив элементов в Javascript? - PullRequest
7 голосов
/ 25 ноября 2008

У меня есть трехэтапный процесс, который полностью зависит от JavaScript и Ajax для загрузки данных и анимации процесса от одного шага к следующему. Чтобы еще больше усложнить ситуацию, переход (вперед и назад) между шагами анимирован :-(. По мере того, как пользователь продвигается через якорь процесса, показывая текущий шаг и предыдущие шаги. Если они нажимают на предыдущий шаг, то он возвращает их к предыдущий шаг.

Прямо сейчас весь процесс (вперед и назад) работает правильно, если вы начинаете с шага 1, но если перейти прямо к шагу 3, то якоря для шага 1 и шага 2 также выполняют то же действие, что и шаг 3.

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

for (var i = 0; i < profile.current + 1; i++) {
    if ($('step_anchor_' + i).innerHTML.empty()) {
        var action = profile.steps[i].action;
        var dao_id = profile.steps[i].dao_id;

        $('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
        $('step_anchor_' + i).observe('click', function(){
            pm.loadData(action, dao_id, true);
        });

        Effect.Appear('step_anchor_' + i, {
            duration: 1,
            delay: (down_delay++)
        });
    }
}

Я знаю, что проблема заключается в том, как передаются параметры action и dao_id. Я также пытался передать profile.steps [i] .action и profile.steps [i] .dao_id, но в этом случае оба профиль и я или, по крайней мере, я вне области.

Как мне сделать так, чтобы я мог правильно назначить параметры для действия и dao_id для каждого шага? (Если это имеет какое-то значение, мы используем Prototype и Scriptaculous)

Ответы [ 2 ]

7 голосов
/ 25 ноября 2008

Ваша цепочка замыкания вызывает ваши проблемы. Объявляя встроенную функцию-обработчик, вы создали замыкание. Очевидно, вы сделали это, чтобы воспользоваться преимуществом цикла.

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

Вы пытаетесь передать, а затем использовать «action» и «dao_id» для своего закрытия, но вы передаете здесь ссылки, а не значения. Поэтому, когда ваши замыкания (обработчики) вызываются, они используют значение, которое ссылка была назначена последней. В вашем случае обработчик шага 3.

Правила области видимости закрытия достаточно запутанные, но вы также можете быть смущены тем фактом, что «action» и «dao_id» все еще живы, даже если блок цикла завершил выполнение. Ну, в JavaScript нет такой вещи, как область видимости блока. После объявления переменной она доступна до конца функции или до тех пор, пока она не будет удалена. В зависимости от того, что наступит раньше.

Все, что сказано, вам нужно разорвать цепь прицела. Вот два способа сделать это:

Попробуйте это:

for (var i = 0; i < profile.current + 1; i++) {
    if ($('step_anchor_' + i).innerHTML.empty()) {
        var action = profile.steps[i].action;
        var dao_id = profile.steps[i].dao_id;

        $('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
        $('step_anchor_' + i).observe('click', function(a, b){
                return function(){pm.loadData(a, b, true)};
        }(action, dao_id));

        Effect.Appear('step_anchor_' + i, {
                duration: 1,
                delay: (down_delay++)
        });
    }
}

Или это:

function createHandler(action, dao_id) {
    return function(){pm.loadData(action, dao_id, true);};
} 

/* snip - inside some other function */
for (var i = 0; i < profile.current + 1; i++) {
    if ($('step_anchor_' + i).innerHTML.empty()) {
        var action = profile.steps[i].action;
        var dao_id = profile.steps[i].dao_id;

        $('step_anchor_' + i).innerHTML = profile.steps[i].anchor;
        $('step_anchor_' + i).observe('click', createHandler(action, dao_id));
        Effect.Appear('step_anchor_' + i, {
                duration: 1,
                delay: (down_delay++)
        });
    }
}
0 голосов
/ 25 ноября 2008

Во-первых, запомните область выполнения в событии click. Ключевое слово this в этом контексте относится к элементу, по которому щелкают. Есть ли способ определить dao_id по элементу, по которому щелкнули?

...