React Hooks 从 onMouseLeave 淡出模态效果

React Hooks fade out effect on modal from onMouseLeave

这对大多数人来说应该是一件容易的事。从按钮(由 onMouseEnter 触发)打开后的模态 window 需要在触发 onMouseLeave 后淡出效果。模态“绿色方块”根本不应该移动它的位置,而只是在它触发 onMouseLeave 或 setOpenFalse 时淡出。他们的风格顺风顺水 css。提前致谢 ‍☠️

沙盒在这里 - https://codesandbox.io/s/modal-transition-clicked-1egnp?file=/src/styles.css:0-191

import React from "react";
import classNames from "classnames";
import { useState, Fragment } from "react";
import { useBoolean } from "./hooks/useBoolean";
import "./styles.css";

export const Actions = ({ defaultSelected = "like" }) => {
  const [selected, setSelected] = useState(defaultSelected);
  const [isOpen, setOpenTrue, setOpenFalse] = useBoolean();

  return (
    <div className="relative rounded">
      <button
        onMouseEnter={setOpenTrue}
        onMouseLeave={setOpenFalse}
        className={classNames("flex items-center gap-2 rounded px-2 py-1", {
          "": isOpen
        })}
      >
        {selected && <Fragment>open modal</Fragment>}
        {isOpen && (
          <div className="absolute mt-20 left-0 flex justify-center items start h-12">
            <div className="bg-green-700 w-24 h-36 shadow grid grid-flow-col  px-2 py-1 gap-2 animate-mount"></div>
          </div>
        )}
      </button>
    </div>
  );
};

export default Actions;

.animate-mount {
  animation: mount 0.4s linear;
}

@keyframes mount {
  0% {
    opacity: 0;
    transform: translateY(50%);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

有点micromanage-y,但您可以再添加两个状态来跟踪按钮元素何时进入和退出。

  1. 设置模态打开并在鼠标输入时设置输入,在鼠标离开时设置输入 false,设置退出时为真,然后设置超时以随后设置打开和退出为假。
  2. 创建一个 .animate-unmount 仅对不透明度设置动画的动画。

卸载动画和 setTimeout 的持续时间应该大致相同。

styles.css

.animate-mount {
  animation: mount 0.4s linear;
}

@keyframes mount {
  0% {
    opacity: 0;
    transform: translateY(50%);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.animate-unmount {
  animation: unmount 0.5s ease-in-out;
}

@keyframes unmount {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

Reactions.js

export const Actions = ({ defaultSelected = "like" }) => {
  const [selected, setSelected] = useState(defaultSelected);
  const [isOpen, setOpenTrue, setOpenFalse] = useBoolean();
  const [isEntered, setEnteredTrue, setEnteredFalse] = useBoolean();
  const [isExited, setExitedTrue, setExitedFalse] = useBoolean();

  return (
    <div className="relative rounded">
      <button
        onMouseEnter={() => {
          setOpenTrue();
          setEnteredTrue();
        }}
        onMouseLeave={() => {
          setEnteredFalse();
          setExitedTrue();
          setTimeout(() => {
            setOpenFalse();
            setExitedFalse();
          }, 500);
        }}
        className={classNames("flex items-center gap-2 rounded px-2 py-1", {
          "": isOpen
        })}
      >
        {selected && <Fragment>open modal</Fragment>}
        {isOpen && (
          <div className="absolute mt-20 left-0 flex justify-center items start h-12">
            <div
              className={classNames(
                "bg-green-700 w-24 h-36 shadow grid grid-flow-col  px-2 py-1 gap-2",
                {
                  "animate-mount": isEntered,
                  "animate-unmount": isExited
                }
              )}
            ></div>
          </div>
        )}
      </button>
    </div>
  );
};