循环超时更改图标

Changing icons with timeout in a loop

我有以下代码循环遍历 table 中的每条记录并将保存图标设置为复选标记。

2 秒后它应该变回保存图标。除了它没有。

我对其他按钮也使用了完全相同的方法,并且有效。所以我怀疑它与循环遍历每条记录的速度有关。虽然 setTimeout 应该是异步的...

有更好的方法吗?每个按钮都应该单独行动。我的最后一招是编写一个函数来更改页面上的所有图标,但我不想这样做。

const iconToggle = () => {
    const isCheckIcon = btn.firstElementChild.classList.contains('fa-check');
    if (isCheckIcon) {
        btn.innerHTML = '<i class="fa fa-save fa-2x"></i>';
    } else {
        btn.innerHTML = '<i class="fa fa-check fa-2x"></i>';
    }
}

for (row = 0; row < table.rows.length; row++) {
    currentRow = table.rows.item(row);

    ...

    returncode = save_row();

    btn = currentRow.getElementsByClassName('record-save')[0].firstElementChild;
    if (returncode == 0) {
        iconToggle();
        setTimeout(iconToggle, 2000);
    }
}

编辑:

$('.table-save-all').on('click', 'i', function() {
    var table = document.getElementById('edit_history_table_body');

    const iconToggle = (abtn, state) => {
        if (state == "save") {
            abtn.innerHTML = '<i class="fa fa-save fa-2x"></i>';
        } else if (state == "check") {
            abtn.innerHTML = '<i class="fa fa-check fa-2x"></i>';
        }
    }

    var currentRow, key, TotalNoBreakDec, OvertimeDec, TotalDec, StartDec, HourSchedule, returncode, btn;

    // loop through each row of the table.
    for (row = 0; row < table.rows.length; row++) {
        currentRow = table.rows.item(row);

        ...

        returncode = save_row();

        btn = currentRow.getElementsByClassName('record-save')[0].firstElementChild;
        if (returncode == 0) {
            iconToggle(btn, "check");
            setTimeout(() => { iconToggle(btn, "save") }, 2000);
        }
    }

    btn = document.getElementsByClassName('table-save-all')[0].firstElementChild;
    iconToggle(btn, "check");
    setTimeout(() => { iconToggle(btn, "save") }, 2000);
});

您应该将要更改的 btn 作为参数传递给 iconToggle() 方法。目前,您的循环抛出所有按钮并重新分配——看似全局的——btn 变量。因此,一旦触发重置图标的超时,btn 可能会分配给您的按钮的最后一个,并且在超时中多次调用 iconToggle 只会切换此按钮。

此外,我建议将所需的状态传递到您的 iconToggle 方法中,以便它始终清楚,正在发生什么变化,并且 iconToggle 的错误调用不会以不受欢迎的方式更新您的界面。

const iconToggle = (abtn, state) => {
    if (state == "save") {
        abtn.innerHTML = '<i class="fa fa-save fa-2x"></i>';
    } else if (state == "check") {
        abtn.innerHTML = '<i class="fa fa-check fa-2x"></i>';
    }
}
for (row = 0; row < table.rows.length; row++) {
    currentRow = table.rows.item(row);

    ...

    returncode = save_row();

    const btn = currentRow.getElementsByClassName('record-save')[0].firstElementChild;
    if (returncode == 0) {
        iconToggle(btn, "save");
        setTimeout(() => {iconToggle(btn, "check")}, 2000);
    }
}

编辑关于您的评论和您答案中的更新代码:

将你的代码与我的进行比较。你会看到我有

const btn = ... 

在循环体内,而你只有

btn = ... 

因此,这行代码

setTimeout(() => {iconToggle(btn, "check")}, 2000);

在您的版本中,将引用在循环体外部某处声明的 btn 变量(您未显示位置)。但是当你在循环迭代期间和循环之后不断更新这个 btn 变量时,btn 最终指向这个元素

 btn = document.getElementsByClassName('table-save-all')[0].firstElementChild;

这就是元素,超时回调中的所有 iconToggles 都适用。

在循环体内声明 btn 变量——或者在 if 的体内更好——它会起作用。

if (returncode == 0) {
    const btn = currentRow.getElementsByClassName('record-save')[0].firstElementChild;
    iconToggle(btn, "save");
    setTimeout(() => {iconToggle(btn, "check")}, 2000);
}

所有变量都应该在尽可能小的范围内定义,以防止此类错误。