Javascript - динамически назначать событие onclick в цикле - PullRequest
9 голосов
/ 18 февраля 2011

У меня очень простая HTML-страница с кодом js:

<html>
    <head>
        <title></title>
    </head>
    <body>

        <div id="divButtons">

        </div>

        <script type="text/javascript">
            var arrOptions = new Array();

            for (var i = 0; i < 10; i++) {
                arrOptions[i] = "option" + i;
            }

            for (var i = 0; i < arrOptions.length; i++) {
                var btnShow = document.createElement("input");
                btnShow.setAttribute("type", "button");
                btnShow.value = "Show Me Option";
                var optionPar = arrOptions[i];
                btnShow.onclick = function() {
                    showParam(optionPar);
                }

                document.getElementById('divButtons').appendChild(btnShow);
            }

            function showParam(value) {
                alert(value);
            }        
        </script>
    </body>
</html>

Эта страница связывает 10 кнопок, но при нажатии на любую кнопку всегда отображается предупреждение «option9». Как можно назначить событие onclick для показа соответствующей опции!?

Спасибо!

Ответы [ 7 ]

31 голосов
/ 18 февраля 2011

Вам нужно будет сделать что-то вроде этого:

btnShow.onclick = (function(opt) {
    return function() {
       showParam(opt);
    };
})(arrOptions[i]);
2 голосов
/ 18 февраля 2011

Учтите, что при выполнении функции onclick () все, что у нее есть, это:

showParam(optionPar);

, дословно.OptionPar будет разрешен во время выполнения события click, и в этот момент он, скорее всего, будет последним значением, которое вы ему присвоили.Как правило, вы должны избегать передачи переменных таким способом.

Проблема, которую вы пытаетесь решить, лучше всего решить, переписав кусок, такой как:

            btnShow.value = "Show Me Option";
            var optionPar = arrOptions[i];
            btnShow.optionPar = optionPar;
            btnShow.onclick = function(e) {
                // if I'm not mistaking on how to reference the source of the event.
                // and if it would work in all the browsers. But that's the idea.
                showParam(e.source.optionPar);
            }
1 голос
/ 24 января 2017

Принятый ответ правильный, но я чувствую, что никакого реального объяснения сделано не было.

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

Переменная 'i' увеличивается на 1 за каждую итерацию цикла, и событие нажатия на самом деле не выполняется , применяется ли оно только к элементу a, оно суммируется до длины arrOptions, равной 10.

Итак, цикл продолжается до тех пор, пока 'i' не станет 10, Затем, всякий раз, когда вызывается событие нажатия, оно принимает значение i, равное 10.

сейчас, для решения, В решении мы используем замыкание, поэтому, когда мы применяем значение 'i' к событию нажатия элемента a, оно фактически получает точное значение i во времени.

Внутренняя функция события onclick создает замыкание, в котором она ссылается на параметр (arrOptions [i]), означающий, что фактическая переменная i находится в нужный момент.

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

1 голос
/ 02 мая 2016

Принятый ответ, кажется, работает, но, похоже, сбивает с толку и несколько громоздкий способ сделать это Возможно, лучшим способом будет использование атрибута данных для элемента, для которого вы хотите назначить прослушиватель событий. Это просто, легко понять и намного меньше кода. Вот пример:

btnShow.data = arrOptions[i];

btnShow.onclick = function() {
  showParam(this.data);
}
1 голос
/ 14 августа 2014

Для jquery, посмотрите добавление данных о событиях в разделе API :

...
for (var i = 0; i < arrOptions.length; i++) {

    $('<input id="btn" type="button" value="Show Me Option"><input>').appendTo("#divButtons")

    $('#btn').bind("click", {
        iCount: i},
    function(event) {
        showParam(arrOptions[iCount]);
    });
}
1 голос
/ 17 июля 2014

Я присоединяю обработчик события:

        window.onload = function() {
            var folderElement;
            tagFolders = document.getElementById("folders");
            for (i = 0; i < folders.length; i++) {
                folderElement = folderButtons[i];
                folderElement = document.createElement("button");
                folderElement.setAttribute("id", folders[i]);
                folderElement.setAttribute("type", "button");
                folderElement.innerHTML = folders[i];
                if (typeof window.addEventListener !== "undefined") {
                    folderElement.addEventListener("click", getFolderElement, false);
                } else {
                    folderElement.attachEvent("onclick", getFolderElement);
                }
                tagFolders.appendChild(folderElement);
            }

, который может извлечь что-либо из элемента, вызвавшего событие:

// This function is the event handler for the folder buttons.
function getFolderElement(event) {
    var eventElement = event.currentTarget;
    updateFolderContent(eventElement.id);
}

, и в этом случае вам необходимо встроить опцию вэлемент / тег.В моем случае я использую идентификатор.

0 голосов
/ 25 апреля 2015

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

btnShow.onclick = new Function("", "showParam(" + arrOptions[i] + ");");

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

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