Javascript-динамически назначать событие onclick в цикле

У меня очень простая 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 ответов


вам придется сделать что-то вроде этого:

btnShow.onclick = (function(opt) {
    return function() {
       showParam(opt);
    };
})(arrOptions[i]);

рассмотрим тот факт, что при выполнении функции 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);
            }

прикрепить обработчик событий:

        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);
}

в этом случае вы должны встроить опцию внутри элемента / тега. В моем случае я использую id.


для 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]);
    });
}

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

btnShow.data = arrOptions[i];

btnShow.onclick = function() {
  showParam(this.data);
}

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

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

переменная "i" увеличивается на 1 за итерацию цикла, и событие on-click фактически не выполняется, применяется ли только к элементу a, он получает суммировать до длины arrOptions, которая равна 10.

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

теперь, для решения, в решении мы используем закрытие, так что, когда мы применяем значение " i " к событию on-click элемента a, он фактически получает точное значение i во времени.

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

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


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

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

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