код в setTimeout () не выполняется при многократном вызове - PullRequest
0 голосов
/ 01 апреля 2020

У меня есть следующая функция:

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 ]

0 голосов
/ 03 апреля 2020

В случае, если кто-то сталкивается с этим, вот что я в итоге сделал (спасибо, @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 и т. д. c.

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

В моем случае это довольно просто, потому что у меня есть только один переход "transform" для элемента. Кроме того, я понятия не имею, если количество eventListeners становится проблемой производительности для больших таблиц. Функция setTimeout () теперь вообще не нужна, в deleteFood () я теперь только запускаю анимацию и удаляю элемент из моей базы данных:

function DeleteFood(index) {
  // animate
  document.getElementById(index).style.transform = 'translate(500px, 0)';

  // delete from airtable
  foodList[index].destroy();
}
0 голосов
/ 01 апреля 2020

Как вы заметили, если вы нажимаете кнопку «Удалить» очень быстро, удаляется только вторая, и причина этого в том, что переменная индекса перезаписывается до того, как истечет время ожидания, поэтому вторая - единственная, которая удаляется.

Вы можете немедленно удалить элемент, а затем оставить тайм-аут для простого сброса списка после завершения анимации. Или добавьте прослушиватель для завершения перехода, чтобы удалить элемент из списка вместо ожидания по таймауту. Если вы хотите прослушать переходы, а многие ответы устарели, вы можете просмотреть

Как нормализовать функции перехода CSS3 в разных браузерах?

...