【问题标题】:How to reverse animation when prop is false styled components当道具是错误样式的组件时如何反转动画
【发布时间】:2020-05-27 22:06:22
【问题描述】:

我将一个 open 属性传递给样式化组件,以便为汉堡图标创建动画。 这是代码

const StyledBurger = styled.button`
  display: flex;
  flex-direction: column;
  justify-content: center;
  border: 0;
  background-color: ${colors.cobaltBlue};
  border-radius: 2.7px;
  cursor: pointer;
  div {
    width: 27px;
    height: 3px;
    margin: 1.5px;
    transition: all 0.2s linear;
    border-radius: 1.4px;
    background-color: ${colors.white};
    :first-child {
      ${({ open }) => open && firstOpenAnimation};
    }
    :nth-child(2) {
      opacity: ${({ open }) => (open ? '0' : '1')};
    }
    :nth-child(3) {
      ${({ open }) => open && seconOpenAnimation}
    }
  }
`;

const firstOpenKeyframe = keyframes`
  50% {
    transform: translateY(6px) rotate(0);
  }
  100% {
    transform: translateY(6px) rotate(45deg);
  }
`;

const secondOpenKeyframe = keyframes`
  50% {
    transform: translateY(-6px) rotate(0);
  }
  100% {
    transform: translateY(-6px) rotate(-45deg);
  }
`;

const firstCloseKeyFrame = keyframes`
  50% {
    transform:translateY(0) rotate(-45deg);
  }
  100% {
    transform:translateY(-6px) rotate(-45deg)  ;
  }
`;

const firstOpenAnimation = css`
  animation: 0.3s linear ${firstOpenKeyframe} forwards;
`;

const seconOpenAnimation = css`
  animation: 0.3s linear ${secondOpenKeyframe} forwards;
`;

const firstCloseAnimation = css`
  animation: 0.3s linear ${firstCloseKeyFrame} forwards;
`;

export default StyledBurger;

基本上我想要的是如果菜单未打开以反转第一次单击后创建的动画。 我尝试根据 prop open 对动画关键帧进行条件渲染,但是当页面加载时会立即创建未打开的动画,因为它满足 false。 我可以做些什么来解决这个问题并在未点击时创建相反的动画

【问题讨论】:

    标签: css reactjs styled-components


    【解决方案1】:

    进行一些更正,它应该都能正常工作。

    • 使用状态切换打开并将其作为道具发送到您的样式组件
    • 对动画使用三元(不仅仅是&&)${({ open }) => (open ? firstOpenAnimation : firstCloseAnimation)}
    • 实现缺少关闭第二个动画

    working copy of your code is here

    工作代码sn-p

    const StyledBurger = styled.button`
      display: flex;
      flex-direction: column;
      justify-content: center;
      border: 0;
      background-color: red;
      border-radius: 2.7px;
      cursor: pointer;
      height: 30px;
      div {
        width: 27px;
        height: 3px;
        margin: 1.5px;
        transition: all 0.2s linear;
        border-radius: 1.4px;
        background-color: white;
        :first-child {
          ${({ open }) =>
            open !== null && (open ? firstOpenAnimation : firstCloseAnimation)}
        }
        :nth-child(2) {
          opacity: ${({ open }) => (open ? "0" : "1")};
        }
        :nth-child(3) {
          ${({ open }) =>
            open !== null && (open ? seconOpenAnimation : secondCloseAnimation)}
        }
      }
    `;
    
    const firstOpenKeyframe = keyframes`
      50% {
        transform: translateY(6px) rotate(0);
      }
      100% {
        transform: translateY(6px) rotate(45deg);
      }
    `;
    
    const secondOpenKeyframe = keyframes`
      50% {
        transform: translateY(-6px) rotate(0);
      }
      100% {
        transform: translateY(-6px) rotate(-45deg);
      }
    `;
    
    const firstCloseKeyFrame = keyframes`
      50% {
        transform:translateY(0) rotate(-45deg);
      }
      100% {
        transform:translateY(0) rotate(0)  ;
      }
    `;
    const secondCloseKeyFrame = keyframes`
      50% {
        transform:translateY(0) rotate(-45deg);
      }
      100% {
        transform:translateY(0) rotate(0)  ;
      }
    `;
    
    const firstOpenAnimation = css`
      animation: 0.3s linear ${firstOpenKeyframe} forwards;
    `;
    
    const seconOpenAnimation = css`
      animation: 0.3s linear ${secondOpenKeyframe} forwards;
    `;
    const secondCloseAnimation = css`
      animation: 0.3s linear ${secondCloseKeyFrame} forwards;
    `;
    
    const firstCloseAnimation = css`
      animation: 0.3s linear ${firstCloseKeyFrame} forwards;
    `;
    export default function App() {
      const [open, setOpen] = useState(null);
    
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <StyledBurger onClick={() => setOpen(prev => !prev)} open={open}>
            <div />
            <div />
            <div />
          </StyledBurger>
        </div>
      );
    }
    
    

    【讨论】:

    • 这仍然会在渲染时执行 firstCloseAnimation
    • 好的 - 将open 的初始状态设置为false .. 像这样const [open, setOpen] = useState(false); ...我已经更新了答案以及沙箱中的代码...
    • 感谢您的宝贵时间,但如果您刷新它,您仍会从沙箱中看到动画正在发生,这是因为我们正在向样式化组件发送一个条件,即 true 或 false 并且它呈现为 false动画
    • 我明白你的意思....好的 - 保持初始状态为空,如果为空则不做动画......否则做通常的三元......我已经更新了答案以及沙盒(刷新它)....如果不是,请告诉我它不起作用
    • 这工作得很好,现在我试图在未点击时创建完全相反的结果,我无法实现它
    猜你喜欢
    • 1970-01-01
    • 2021-10-27
    • 2017-10-20
    • 1970-01-01
    • 2020-08-06
    • 2021-05-10
    • 2020-07-07
    • 2019-03-03
    • 2020-11-09
    相关资源
    最近更新 更多