简体   繁体   English

设置函数以使用HTML / Javascript中的字符串在循环内的按钮上单击onclick

[英]Setting functions to onclick for Buttons within loops with strings in HTML/Javascript

 var RelevantDiv = document.getElementById("RelevantDiv");
 for (var i = 0; i < 5; i++) {
    for (var j = 0; j < 5; j++) {
       var NewButton = document.createElement("NewButton");
       var IdString = "ID" + i + "_"  +j;
       NewButton.onclick = function() { DoStuff(IdString) };
       RelevantDiv.appendChild(NewButton);
    }
 } 

 function DoStuff(IdForStuff) {
    // Does stuff with id 
 }

The problem is that every time the NewButton.onclick is set, that it is setting it to the final IdString which is "ID4_4" . 问题在于,每次设置NewButton.onclick ,都会将其设置为最终的IdString ,即"ID4_4"

The problem here is that, when the handler you assign runs, the loop has already looped through all iterations, and the variable at that point will be at its final state. 这里的问题是,当您分配的处理程序运行时,该循环已经遍历了所有迭代,并且此时的变量将处于其最终状态。 To avoid this, you need to use a lock. 为避免这种情况,您需要使用锁。 It involves a self-executing function (function () { // code })() which saves the current state of the variable. 它涉及一个自执行函数(function () { // code })() ,该(function () { // code })()保存变量的当前状态。 When the variable in the current iteration, for example State 2 is given as an argument to the self-executing function, the scope of the function will save this state. 当当前迭代中的变量(例如, State 2 )作为自执行函数的参数给出时,该函数的作用域将保存该状态。 When the for loop continues, the original variable will still change, but the scope of the new "inner function" will keep the value "locked". 当for循环继续时,原始变量仍将更改,但是新的“内部函数”的范围将保持值“锁定”。 So even when the loop-variable will in the end be at its 4th state, the locked variable will still be in state 2. 因此,即使循环变量最终处于其第4状态,锁定变量仍将处于状态2。

for (var i = 0; i < 5; i++) {
    button.addEventListener ("click", function () {
        // Here, i would normally always be 5
        (function (lockedIndex) {
            // This lock will make i the way it should be
            // You have to use lockedIndex instead of i
        })(i)
    });
}

For your code, this would look something like: 对于您的代码,这看起来像:

 var RelevantDiv = document.getElementById("RelevantDiv");
 for (var i = 0; i < 5; i++) {
    for (var j = 0; j < 5; j++) {
        (function (ix, jx) {
          var NewButton = document.createElement("NewButton");
          var IdString = "ID" + ix + "_"  +jx;
          NewButton.onclick = function() { DoStuff(IdString) };
          RelevantDiv.appendChild(NewButton);
        })(i, j)
    }
 } 

 function DoStuff(IdForStuff) {
    // Does stuff with id 
 }

Worth noting, that you won't have such problems if you use let or const instead of var : 值得注意的是,如果使用letconst而不是var ,则不会出现此类问题:

for (let i = 0; i < 5; i++) {
    for (let j = 0; j < 5; j++) {
       const NewButton = document.createElement("NewButton");
       const IdString = "ID" + i + "_"  +j;
       NewButton.onclick = function() { DoStuff(IdString) };
       RelevantDiv.appendChild(NewButton);
    }
}

Your underlying issue is that the variable being used within the onclick callback, IdString , is having its declaration hoisted to the top of the current scope, ie the function it's running within. 您的根本问题是,在onclick回调IdString使用的变量的声明已提升到当前作用域的顶部,即它正在其中运行的函数。 That means that every time you're within the loop, its value is overwritten - it's functionally the same as this: 这意味着每次您进入循环时,其值都会被覆盖-它的功能与此相同:

var IdString;

var RelevantDiv = document.getElementById("RelevantDiv");
for (var i = 0; i < 5; i++) {
   for (var j = 0; j < 5; j++) {
      var NewButton = document.createElement("NewButton");
      IdString = "ID" + i + "_"  +j;
      NewButton.onclick = function() { DoStuff(IdString) };
      RelevantDiv.appendChild(NewButton);
   }
} 

You need to ensure that you capture the right value of IdString when you need it, which is typically done through the use of a closure: 您需要确保在需要时捕获IdString的正确值,这通常是通过使用闭包来完成的:

var RelevantDiv = document.getElementById("RelevantDiv");
for (var i = 0; i < 5; i++) {
   for (var j = 0; j < 5; j++) {
      (function(IdString) {
          var NewButton = document.createElement("NewButton");
          NewButton.onclick = function() { DoStuff(IdString) };
          RelevantDiv.appendChild(NewButton);
      })("ID" + i + "_"  +j)
   }
} 

Here we create another inner function to create a new scope to hold each individual IdString value. 在这里,我们创建了另一个内部函数,以创建一个新的范围来保存每个单独的IdString值。 It's then immediately called with the right value for each iteration of the loops. 然后立即为每次循环迭代使用正确的值调用它。 IdString is then captured within this closure, and the correct value will be used within the onclick callback. 然后,在此闭包中捕获IdString ,并将在onclick回调中使用正确的值。


Alternatively, you can bind the argument at the moment you know what the relevant value is: 另外,您可以在知道相关值是什么时绑定参数

var RelevantDiv = document.getElementById("RelevantDiv");
for (var i = 0; i < 5; i++) {
   for (var j = 0; j < 5; j++) {
      var NewButton = document.createElement("NewButton");
      NewButton.onclick = DoStuff.bind(null, "ID" + i + "_"  +j);
      RelevantDiv.appendChild(NewButton);
   }
} 

This does away with both of the inner functions, and directly assigns the onclick event to a copy of the DoStuff function that will have the right argument. 这消除了两个内部函数,并直接将onclick事件分配给具有正确参数的DoStuff函数的副本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM