【问题标题】:How can I add click events to an array of buttons with their position?如何将点击事件添加到按钮数组及其位置?
【发布时间】:2019-11-24 18:22:15
【问题描述】:

我正在尝试添加一个事件,当我单击它时会更改按钮的文本。不过不管我点击哪个按钮,它总是会改变最后一个按钮的文本。

起初我尝试将按钮传递给“pulsar”方法,但总是最后一个按钮是变化的。我认为这可能是变量的引用,所以我尝试传递位置,但同样的情况发生了。

class Buscaminas{
    constructor () {
        this.botones = [];
        for (var i = 0; i < 8; i++) {
            for (var j = 0; j < 7; j++) {
                let boton = document.getElementById(i + "" + j);
                boton.textContent = "Hi";
                boton.onclick = e => {
                    this.pulsar(6*i+j);
                }
                this.botones.push(boton);
            }
        }
    }

    pulsar = (n) => {
        console.log(n);
        this.botones[n].textContent = "Bye";
    }
}

console.log 总是打印 55

【问题讨论】:

  • var ivar j 更改为 let ilet j,因此每个函数中的值将是它们被声明的值,而不是最后的值。
  • 谢谢!我认为因为它们是数字,所以没有必要
  • 如何显示按钮?

标签: javascript html arrays button


【解决方案1】:

你的方法不正确。

在你有很多元素的情况下,你永远不想为每个元素添加一堆单独的事件处理程序。您想在根节点创建单个事件处理程序,每个子元素的点击事件都会冒泡。

在这个例子中,我们有 10 个 div:

<div id="btn-root">
  <input type="button" class="btn" value="1">
  <input type="button" class="btn" value="2">
  <input type="button" class="btn" value="3">
  <input type="button" class="btn" value="4">
  <input type="button" class="btn" value="5">
  <input type="button" class="btn" value="6">
  <input type="button" class="btn" value="7">
  <input type="button" class="btn" value="8">
  <input type="button" class="btn" value="9">
  <input type="button" class="btn" value="10">
</div>

我们有这个简单的代码来监听任何子“.btn”元素的点击:

class Buscaminas {
  constructor() {
    document.querySelector('#btn-root').addEventListener('click', (evt) => {
      evt.target.textContent = Math.random();
    }); 
  }
}

new Buscaminas();

如果您运行它,您会看到每次单击其中一个按钮时,其内容都会被替换为一个随机数。

后期编辑:

假设您想要查找被点击元素的索引。我们仍然不想为每个元素分配单独的事件处理程序,但我们没有提供父元素中目标元素的索引。

为了解决这个问题,我们要搜索#btn-root 的子节点,直到匹配。二进制搜索在这里不起作用,但我们想要比indexOf 更好的东西,它只是进行线性搜索。我们可以做的只是循环一半数组的长度并检查两端。那么我们就可以相当高效的得到索引了。

document.querySelector('#btn-root').addEventListener('click', (ev) => {
  const children = ev.target.parentNode.children;

  for (let i = 0; i < Math.floor(children.length / 2); i++) {
    const lowMatch = ev.target === children[i] && i;
    const highMatch = ev.target === children[children.length - 1 - i] && children.length - 1 - i;
    const index = Number.isInteger(lowMatch) && lowMatch || Number.isInteger(highMatch) && highMatch;

    if (index) {
      ev.target.value = `${index + 1}-${Math.random()}`;
      break;      
    }
  }
});

【讨论】:

  • 请注意,样式为按钮的divs 仍然是div 元素,因此屏幕阅读器和使用键盘导航的人都无法访问。虽然我确实理解您只是提供一个简单的演示,但我认为这些示例也应该考虑到可访问性。在某些时候,有人会使用您的示例来创建生产代码。
  • @Arjan 是的,但您的评论与原始问题完全无关。我在回答中使用 div 来说明事件处理的正确技术。按钮元素仍然使用相同的概念。
  • 我知道我的评论与问题没有直接关系,但与您的回答有关。您可以使用&lt;button&gt; 元素(或&lt;input type="button"&gt;)来展示概念,同时展示按钮应该是需要点击交互的事物的首选。
  • 我不得不将按钮更改为二维数组,所以这种方法有点过于复杂,无法获取 i 和 j。无论如何,谢谢您的回复!我还在学习,我不知道我可以添加这样的 eventListeners,我会记住它以备将来使用
  • @CarmenSirgo 它们被称为模板文字。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…。它是一个相对较新的 ES6 功能,允许轻松构建带有变量的字符串,而无需进行字符串连接。
【解决方案2】:

你可以试试这个:

function sayHello(e) {
  e.target.textContent = "Darth Vader";
}

var buttons = document.querySelectorAll("button");
buttons.forEach(e => e.addEventListener("click", sayHello, false));
<button>Hello</button>
<button>I</button>
<button>Am</button>
<button>Your</button>
<button>Father</button>

【讨论】:

  • 不要这样做。您几乎从不想将单个事件处理程序添加到许多常见元素。除此之外,您的代码仍然不正确。你只需要document.querySelectorAll('.btn').map((el) =&gt; el.addEventListener('click', () =&gt; el.innerHTML = 'whatever'))
  • 您为什么不想为许多常见元素添加单独的事件处理程序?我渴望学习。为什么我的代码不正确,它工作得很好。
  • 考虑效率。如果你有数百个元素,那么拥有一个函数比拥有数百个更有效。不正确,我的意思是它不必要地复杂。虽然我没有在我的示例中包含它,但map 将返回一个元素数组,因此您可以将其分配给一个变量以供将来访问,而无需再次执行 querySelectorAll。
  • 在您发表评论后,我考虑了一下,是的,您是对的。这样做是不明智的。您会提出什么替代方案?就像一个全局 body.document.addEventListener 接受事件对象并在给定函数内进行必要的过滤?
  • Welp,我要再次回答 OP 的问题,因为这有几个方向。对于“更改元素的文本”的情况,我下面的回答是最有效的。但是如果你需要访问被点击元素的索引呢?这变得更加复杂。要回答您的最后一个问题,您需要父处理程序的情况因正在执行的操作而异。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多