所有按钮只影响一个输入而不是各自的输入

All buttons only affect one input instead of respective input

我正在为自己做一个小项目。所以基本上它的主要功能是为每个游戏创建一个基础计数器。

例如:如果有两个玩家,它应该创建三个基地。 (如果这有助于您更好地理解,这是针对纸牌游戏“粉碎”的。)但是当按钮填充时,它们都只影响最后一次输入。我不知道如何让它们影响各自的输入。

我遇到的问题是我点击的每个按钮只影响最后一次输入。

<html>
  <title>  Base Maker  </title>
  <body>  
    <div> 
      <hl>  Score Keeper  </h1>
      <hr>
      
        <input type = "text" placeholder = "How many players?">
      
        <button id = "enter" onclick = "baseMaker()">
        Enter
        </button>
      
      </div>
    
      <p></p>
  
  </body>  
</html>
var parent = document.querySelector("p"); 
var input  = document.querySelector("input"); 
var enter  = document.getElementById("enter");

function baseMaker() 
{ 

  for(var i = 0; i <= input.value; i++) 
  { 

    //base
    var base = document.createElement("p"); 
    base.textContent = "Base " + (i + 1) + ":"; 

    //score
    var score = document.createElement( "input");
    score.setAttribute("id", "score" + i); 
    score.value = 20;

    //upbutton 
    var upButton = document.createElement( "button");
    upButton.textContent = "+";
    upButton.setAttribute("id", "upButton" + i)
    upButton.addEventListener('click', function() {
      score.value++; }); 

    //downbutton 
    var downButton = document.createElement( "button");
    downButton.textContent = "-";
    downButton.setAttribute("id", "downButton" + i)
    downButton.addEventListener('click', function() {
      score.value--; }); 

    //populate data
    parent.appendChild(base);
    parent.appendChild(score);
    parent.appendChild(upButton); 
    parent.appendChild(downButton);

  } 
  input.value = ""; 
}

这对 运行 来说很常见,尤其是在 javascript 中不使用框架时。

我不确定为什么会发生这种情况,但是当直接在循环中定义函数时,这些创建的函数的闭包在最后一次迭代后会变成任何形式。我相信这是因为每个回调函数的闭包仅在最后一次迭代之后包含循环的函数执行结束时才“密封”(因为缺少更好的词)。不过,这真的超出了我的范围。

有一些简单的方法可以避免这种行为:

  • 使用绑定确保使用正确的输入调用回调(在底部的解决方案中使用)
  • 创建一个为您创建处理程序函数的函数,并在循环体中使用它
function createIncrementHandler(input, howMuch){
    return () => input.valueAsNumber += howMuch;
}
/// then in your loop body:
downButton.addEventListener('click', createIncrementHandler(score, 1));
  • 使用处理程序中的事件参数获取正确的输入
downButton.addEventListener('click', (event) => event.target.valueAsNumber += 1);
  • 把整个循环体做成一个函数,例如:
function createInputs(i) {
    //base
    var base = document.createElement("p");
    base.textContent = "Base " + (i + 1) + ":";

    //score
    var score = document.createElement("input");
    score.type = "number";
    score.setAttribute("id", "score" + i);
    score.value = 20;

    //upbutton 
    var upButton = document.createElement( "button");
    upButton.textContent = "+";
    upButton.setAttribute("id", "upButton" + i)
    upButton.addEventListener('click', function() {
    score.value++; }); 

    //downbutton 
    var downButton = document.createElement( "button");
    downButton.textContent = "-";
    downButton.setAttribute("id", "downButton" + i)
    downButton.addEventListener('click', function() {
    score.value--; }); 

    //populate data
    parent.appendChild(base);
    parent.appendChild(score);
    parent.appendChild(upButton);
    parent.appendChild(downButton);
}

这是可能的修复方法之一的完整示例。

<html>
<title> Base Maker </title>

<body>
    <div>
        <hl> Score Keeper </h1>
            <hr>

            <input type="text" placeholder="How many players?">

            <button id="enter" onclick="baseMaker()">
                Enter
            </button>

    </div>

    <p></p>

    <script>
        var parent = document.querySelector("p");
        var input = document.querySelector("input");
        var enter = document.getElementById("enter");

        function incrementInput(input, byHowMuch) {
            input.valueAsNumber = input.valueAsNumber + byHowMuch;
        }

        function baseMaker() {

            for (var i = 0; i <= input.value; i++) {

                //base
                var base = document.createElement("p");
                base.textContent = "Base " + (i + 1) + ":";

                //score
                var score = document.createElement("input");
                score.type = "number";
                score.setAttribute("id", "score" + i);
                score.value = 20;

                //upbutton 
                var upButton = document.createElement("button");
                upButton.textContent = "+";
                upButton.setAttribute("id", "upButton" + i)
                upButton.addEventListener('click', incrementInput.bind(null, score, 1));

                //downbutton 
                var downButton = document.createElement("button");
                downButton.textContent = "-";
                downButton.setAttribute("id", "downButton" + i)
                downButton.addEventListener('click', incrementInput.bind(null, score, -1));

                //populate data
                parent.appendChild(base);
                parent.appendChild(score);
                parent.appendChild(upButton);
                parent.appendChild(downButton);

            }
            input.value = "";
        }
    </script>
</body>
</html>

我会这样做:

const
  AllBases    = document.querySelector('#bases')
, bt_Start    = document.querySelector('#game-go')
, bt_newGame  = document.querySelector('#new-game')
, playerCount = document.querySelector("#play-start > input")
  ;
playerCount.value = ''
playerCount.focus()

playerCount.oninput = () =>
  {
  playerCount.value.trim()
  bt_Start.disabled = (playerCount.value === '' || isNaN(playerCount.value))
  playerCount.value = (bt_Start.disabled) ? ''
                    : (playerCount.valueAsNumber > playerCount.max) ? playerCount.max
                    : (playerCount.valueAsNumber < playerCount.min) ? playerCount.min
                    : playerCount.value
  }
bt_newGame.onclick = () =>
  {
  playerCount.value    = ''
  playerCount.disabled = false
  bt_Start.disabled    = true
  bt_newGame.disabled  = true
  AllBases.innerHTML   = ''
  playerCount.focus()
  }
bt_Start.onclick = () =>
  { 
  playerCount.disabled = true
  bt_Start.disabled    = true
  bt_newGame.disabled  = false

  for(let i = 0; i <= playerCount.valueAsNumber; i++) 
    { 
    let base        = document.createElement('p')
    base.countValue = 20  // create a counter property on <p>
    base.innerHTML  = `Base ${i+1} : <span>${base.countValue}</span> <button>+</button> <button>&#8722;</button>\n`
    AllBases.appendChild(base)
    } 
  }
AllBases.onclick = ({target}) =>
  {
  if (!target.matches('button')) return // verify clicked element

  let countElm = target.closest('p')
  if (target.textContent==='+')  countElm.countValue++
  else                           countElm.countValue--
  countElm.querySelector('span').textContent = countElm.countValue
  }
#bases p span {
  display       : inline-block;
  width         : 6em;
  border-bottom : 2px solid aqua;
  padding-right : .2em;
  text-align    : right;
  margin        : 0 .3em;
  }
#bases p button {
  width  : 2em;
  margin : 0 .1em;
  cursor : pointer;
  }
<hr>
<hl>  Score Keeper  </h1>
<hr>
<div id="play-start" > 
  <input type="number" placeholder="How many players?" min="2" max="4">
  <button id="game-go"  disabled> Enter </button>
  <button id="new-game" disabled> new </button>
</div>
<hr>
<div id="bases"></div>

如果有帮助,我可以添加更多解释