forEach代码不起作用,但是两个不同的forEach函数中的相同代码却起作用,为什么?

时间:2019-01-16 13:16:13

标签: javascript arrays foreach onclick

我有一个名为“ filteredTasks”的数组,对于每个任务,我想在Div中创建一个按钮,并向该按钮添加onclick函数。我创建了一些代码(您可以在下面的第一个块中看到)来执行此操作。没用的是,按钮创建正确,但是onclick函数仅添加到最后一个按钮。 当我使用完全相同的代码,但分成两个不同的forEach回调(您也可以在下面的第二部分中查看)时,它确实起作用。 简而言之,当尝试创建按钮并在创建时向每个按钮添加onclick函数时,只有最后一个按钮才能正确接收onclick函数。但是,当我首先创建所有按钮,然后向每个按钮添加onclick函数时,它确实起作用。我不知道为什么会这样。这里有什么更好的开发人员可以指出为什么? 非常感谢!

        filteredTasks.forEach(function(task) {
            var buttonId = task.taskName.replace(/\s/g, '') + 'Button'
            var taskHTML = `<button class="taskButton" id="${buttonId}">${task.taskName}</button>`;
            taskDiv.innerHTML += taskHTML;
            var button = document.querySelector(`#${buttonId}`);
            button.onclick = function() {performTask(task)};
        });
    };





        filteredTasks.forEach(function(task) {
            var buttonId = task.taskName.replace(/\s/g, '') + 'Button'
            var taskHTML = `<button class="taskButton" id="${buttonId}">${task.taskName}</button>`;
            taskDiv.innerHTML += taskHTML;
        });

        filteredTasks.forEach(function(task) {
            var buttonId = task.taskName.replace(/\s/g, '') + 'Button'
            var button = document.querySelector(`#${buttonId}`);
            button.onclick = function() {performTask(task)};
        });
    };

1 个答案:

答案 0 :(得分:0)

我怀疑这与您处理DOM更新的方式有关。您的代码仅将事件添加到最后一个按钮。这是a known issue with for/loops)。使用forEach代替for / loop would normally fix this,但显然在这种情况下不使用。 (我很欣赏,这有点麻烦。另一位SO成员可能有更详细的技术原因,说明在这种情况下不起作用。)

这就是说,正如您所发现的,分阶段进行此操作要好得多,但是您应该再走几步。它将避免陷入您现在所处的境地,并且会表现得更好。

目前,您正试图在一个循环中实现所有目标:创建任务html,将其添加到DOM,并将事件侦听器添加到新按钮。您应该做的是创建 all HTML,然后将那个添加到DOM,然后使用它们的类同时选择所有按钮并将侦听器添加到它们。

const filteredTasks = [{ taskName: 'bob' },{ taskName: 'dave' }];
const tasks = document.querySelector('#tasks');

// Use `map` to create all the buttons
// I've used a data attribute here instead of an actual id
const html = filteredTasks.map(task => {
  const buttonId = `${task.taskName.replace(/\s/g, '')}Button`;
  return `<button class="taskButton" data-id="${buttonId}">${task.taskName}</button>`;
}).join('');

// Add that HTML to the DOM with one update
tasks.innerHTML = html;

// Grab all the taskButton buttons using their class,
// and add click listeners to them
const buttons = document.querySelectorAll('.taskButton');
[...buttons].forEach(button => button.addEventListener('click', performTask, false));

// `performTask` destructs the event target (clicked button)
// and logs the id 
function performTask(e) {
  const { dataset: { id } } = e.target;
  console.log(id);
}
<div id="tasks"></div>