反应选择菜单打开/关闭的动画

时间:2020-08-21 07:22:24

标签: reactjs react-select

是否可以对菜单的打开和关闭进行动画处理?菜单节点在打开/关闭时被删除或附加到DOM树,因此这会干扰CSS动画。有没有解决的办法?

2 个答案:

答案 0 :(得分:3)

要打开动画,这是相对容易的,只需要使用css将动画添加到<Menu/>组件中即可。

以下示例使用淡入/淡出动画

@keyframes fadeIn {
  0% {
    opacity: 0;
    transform: translateY(2rem);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.menu {
  animation: fadeIn 0.2s ease-in-out;
}

在您的渲染方法中

<Select
  {...}
  components={{
    Menu: (props) => <components.Menu {...props} className="menu" />
  }}
/>

结束动画有点棘手,因为API支持有限。当菜单关闭事件触发时,菜单元素将立即被删除,没有时间运行关闭动画。

因此,我们需要稍微更改关闭事件的行为。策略是让菜单突然像往常一样关闭。但是在此之前,我们将对菜单进行另一个克隆,然后该克隆将运行结束动画并在动画结束时将其自身删除。

// generate unique ID for every Select components
const uniqueId = "select_" + Math.random().toFixed(5).slice(2);

return (
  <Select
    id={uniqueId}
    onMenuClose={() => {
      const menuEl = document.querySelector(`#${uniqueId} .menu`);
      const containerEl = menuEl?.parentElement;
      const clonedMenuEl = menuEl?.cloneNode(true);

      if (!clonedMenuEl) return; // safeguard

      clonedMenuEl.classList.add("menu--close");
      clonedMenuEl.addEventListener("animationend", () => {
        containerEl?.removeChild(clonedMenuEl);
      });

      containerEl?.appendChild(clonedMenuEl!);
    }}
    {...}
  />
);

不要忘记将结束动画附加到正确的CSS类。在这种情况下,menu--close

@keyframes fadeOut {
  0% {
    opacity: 1;
    transform: translateY(0);
  }
  100% {
    opacity: 0;
    transform: translateY(2rem);
  }
}

.menu--close {
  animation: fadeOut 0.2s ease-in-out;
}

最后,您将得到类似的东西

enter image description here

实时演示

Edit React-select Open/Close Animation

答案 1 :(得分:0)

另一种方法是使用 menuIsOpen 道具而不是克隆。

const [isMenuOpen, setIsMenuOpen] = useState(false)
 
const openMenuHandler = async () => {
  await setIsMenuOpen(true)

  const menu = document.querySelector(`#select .menu`)     

  menu.style.opacity = '1'
}

const closeMenuHandler = () => {
  const menu = document.querySelector(`#select .menu`)

  menu.style.opacity = '0'

  setTimeout(() => {
    setIsMenuOpen(false)
  }, 400)
}   

<Select
  menuIsOpen={isMenuOpen}
  onMenuOpen={() => {openMenuHandler()}}
  onMenuClose={() => {closeMenuHandler()}}
/>