首页 > 解决方案 > 在循环中更改带有超时的图标

问题描述

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

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);
});

标签: javascriptsettimeout

解决方案


您应该将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);
}

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


推荐阅读