为了账号安全,请及时绑定邮箱和手机立即绑定

setTimeout() 中的代码在多次调用时不会被执行

setTimeout() 中的代码在多次调用时不会被执行

心有法竹 2022-06-09 10:30:57
我有以下功能:function deleteFood(index) {    // animate    document.getElementById(foodList[index].id).style.transform = 'translate(500px, 0)';    // delete from airtable    foodList[index].destroy();    window.setTimeout(() => {      // delete from state      let newState = foodList.slice();      newState.splice(index, 1);      setFoodList(newState);    }, 500);}基本上有一个列表,用户可以在每个列表条目上单击删除。如果您单击条目上的删除,它会动画,然后在删除时消失。到目前为止,一切正常。但是,如果我非常快地在两个条目上单击删除,则只有第二个被删除。假设我们有 4 个条目(0,1,2,3),我在 1 和 2 上单击删除,然后列表仍然有 0,1,3。所有条目都是动画的,并被称为销毁。我尝试使用承诺无济于事。我怎样才能解决这个问题?
查看完整描述

2 回答

?
跃然一笑

TA贡献1826条经验 获得超6个赞

正如您所指出的,如果您很快单击删除,则只有第二个被删除,原因是索引变量在超时触发之前被覆盖,这就是为什么第二个是唯一被删除的原因。

您可以立即删除该项目,然后在动画完成后保留超时以重置列表。或者,为过渡已结束添加侦听器以从列表中删除项目,而不是等待超时。


查看完整回答
反对 回复 2022-06-09
?
慕斯王

TA贡献1864条经验 获得超2个赞

万一有人遇到这个,这就是我最终做的事情(谢谢@Lynyrd!)


// transition names (found in Modernizr)

let transEndEventNames = {

  'WebkitTransition': 'webkitTransitionEnd', // Saf 6, Android Browser

  'MozTransition': 'transitionend', // only for FF < 15

  'transition': 'transitionend', // IE10, Opera, Chrome, FF 15+, Saf 7+

};

我使用 React,所以我在 useEffect 中添加了事件侦听器,以便在再次获取 foodList 等时自动添加它们。


// add & remove event listeners for transition end

useEffect(() => {

  foodList.forEach((item, index) => {

    if (!document.getElementById(index)) return;

    document

      .getElementById(index)

      .addEventListener(

        transEndEventNames.WebkitTransition,

        handleTransitionEnd

      );

    document

      .getElementById(index)

      .addEventListener(

        transEndEventNames.MozTransition,

        handleTransitionEnd

      );

    document

      .getElementById(index)

      .addEventListener(transEndEventNames.transition, handleTransitionEnd);

  });


  return () => {

    foodList.forEach((item, index) => {

      if (!document.getElementById(index)) return;

      document

        .getElementById(index)

        .removeEventListener(

          transEndEventNames.WebkitTransition,

          handleTransitionEnd

        );

      document

        .getElementById(index)

        .removeEventListener(

          transEndEventNames.MozTransition,

          handleTransitionEnd

        );

      document

        .getElementById(index)

        .removeEventListener(

          transEndEventNames.transition,

          handleTransitionEnd

        );

    });

  };

}, [foodList]);

我决定不尝试根据当前浏览器仅添加一个事件侦听器,但这也是可能的。请记住,每次转换都会触发此侦听器。结果,当有人将鼠标悬停在其中的元素上时(触发了工具提示),我的表格条目被删除。所以不要忘记过滤:


function handleTransitionEnd(event) {

  // only delete element for transform transition

  if (!(event.propertyName === 'transform')) return;

  let newState = foodList.slice();

  newState.splice(event.target.id, 1);

  setFoodList(newState);

}

就我而言,这很容易,因为我在元素上只有一个“变换”过渡。另外,我不知道 eventListener 的数量是否会成为较大表的性能问题。现在根本不需要 setTimeout() 函数,在 deleteFood() 中,我现在只启动动画并从数据库中删除项目:


function DeleteFood(index) {

  // animate

  document.getElementById(index).style.transform = 'translate(500px, 0)';


  // delete from airtable

  foodList[index].destroy();

}


查看完整回答
反对 回复 2022-06-09
  • 2 回答
  • 0 关注
  • 306 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号