react-transition-group 卡片翻转动画

react-transition-group card flip animation

我是 react-transition-group 的新手,我正在尝试制作卡片翻转动画。我能够让第一面翻转,但它不喜欢留在背面的想法。知道我在这里做错了什么吗?

import {useState} from "react";
import {CSSTransition} from "react-transition-group";

import "./styles.css";

export default function App() {
  const [flipped, setFlipped] = useState(false);

  return (
    <div className="card-container">
      <button
        className="card-button"
        onClick={() => setFlipped(!flipped)}
      >
        <CSSTransition
          in={flipped}
          timeout={1000}
          classNames="front-face-transition"
        >
          <div className="card-front">
            <p>front-side</p>
          </div>
        </CSSTransition>
        <CSSTransition
          in={!flipped}
          timeout={1000}
          classNames="back-face-transition"
        >
          <div className="card-back">
            <p>back-side</p>
          </div>
        </CSSTransition>
      </button>
    </div>
  );
}

.App {
  font-family: sans-serif;
  text-align: center;
}

.card-container {
    width: 250px;
    height: 400px;
    padding: 0;
    margin: 0;
}

.card-container .card-button {
    padding: 0;
    margin: 0;
    border: none;
    cursor: pointer;
    width: 100%;
    height: 100%;
    position: relative;
}

.front-face-transition-enter {
    transform-style: preserve-3d;
    transition: all 1000ms ease;
    transform: rotateY(0deg);
}
.front-face-transition-enter-active {
    transform: rotateY(180deg);
}
.front-face-transition-enter-done {
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
}

.back-face-transition-enter {
    transform-style: preserve-3d;
    transition: all 1000ms ease;
    transform: rotateY(0deg);
    display: block;
}
.back-face-transition-enter-active {
    transform: rotateY(-180deg);
    display: block;
}
.back-face-transition-enter-done {
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
}


.card-front {
    display: none;
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    -webkit-backface-visibility: hidden;
    backface-visibility: hidden;
}

此外,这里有一个有效的 codesandbox link 代码以防万一也有帮助。

这里有很多东西要打开。没有一个错误导致您出现问题,但有很多小错误。我会尽力解决这些问题。在大多数情况下,你的 React 是正确的,但 CSS 是你遇到麻烦的地方。

tl;dr:这是一个有效的 code sandbox

  1. 您需要在 active class 上放置转换。这是约定俗成的,但对于您的特定示例,它们可能是卡片元素上的永久属性。
  2. transform-style保留 3d 需要在 3d 元素的父级上
  3. 如果您希望页面加载时正面朝前,那么您的 flipped 逻辑就是倒退的
  4. 你的正面有 display: none,这意味着它根本不可见。
  5. 如果您希望保持变换(180 度转弯),则需要指定 exit-doneenter-done。将这些规则设置为与 active class 具有相同的变换值,这将使动画结束后的一侧“保持原样”。
  6. 背面可见性可以是面部元素的永久属性
  7. 背面的显示块什么也没做——它已经是块了,因为它是一个 div 元素。我想你是想把它放在 card-front 规则中。
  8. 需要在父元素上设置 perspective 属性 才能看到真正的 3d 效果。这是一个像素值,表示观看者与 z space.
  9. 中的元素的距离
  10. 需要对卡片布局进行更多调整才能使其正确。我在下面添加了我的基本样式。
  11. 3d 元素容器的背景(你的例子中的按钮)应该有 transparent 的背景,否则卡片在 3d 中移动时会切穿背景 space。
  12. 在以这种方式旋转的元素上设置一个明确的背景是个好主意,这样动画会更流畅。

我想就这些了。

代码

import { useState } from "react";
import { CSSTransition } from "react-transition-group";

import "./styles.css";

export default function App() {
  const [flipped, setFlipped] = useState(false);

  return (
    <div className="card-container">
      <button className="card-button" onClick={() => setFlipped(!flipped)}>
        <CSSTransition
          in={!flipped}
          timeout={1000}
          classNames="front-face-transition"
        >
          <div className="card-front">
            <p>front-side</p>
          </div>
        </CSSTransition>
        <CSSTransition
          in={flipped}
          timeout={1000}
          classNames="back-face-transition"
        >
          <div className="card-back">
            <p>back-side</p>
          </div>
        </CSSTransition>
      </button>
    </div>
  );
}
body {
  background-color: darkgray;
}

.App {
  font-family: sans-serif;
  text-align: center;
}

.card-container {
  width: 250px;
  height: 400px;
  padding: 0;
  margin: 0;
}

.card-container .card-button {
  padding: 0;
  margin: 0;
  border: none;
  cursor: pointer;
  width: 100%;
  height: 100%;
  position: relative;
  background: transparent;
  transform-style: preserve-3d;
  perspective: 5000px;
}

.card-front,
.card-back {
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  width: 100%;
}

.card-front {
  background: beige;
  position: absolute;
  top: 0;
  left: 0;
}

.card-back {
  background: aliceblue;
}

.front-face-transition-enter {
  transform: rotateY(180deg);
}
.front-face-transition-enter-active {
  transition: all 1000ms ease;
  transform: rotateY(0deg);
}
.front-face-transition-enter-done {
  transform: rotateY(0deg);
}

.front-face-transition-exit {
  transform: rotateY(0deg);
}

.front-face-transition-exit-active {
  transform: rotateY(180deg);
  transition: all 1000ms ease;
}

.front-face-transition-exit-done {
  transform: rotateY(180deg);
}

.back-face-transition-enter {
  transform: rotateY(-180deg);
}
.back-face-transition-enter-active {
  transform: rotateY(0deg);
  transition: all 1000ms ease;
}
.back-face-transition-enter-done {
  transform: rotateY(0deg);
}

.back-face-transition-exit {
  transform: rotateY(0deg);
}

.back-face-transition-exit-active {
  transform: rotateY(-180deg);
  transition: all 1000ms ease;
}

.back-face-transition-exit-done {
  transform: rotateY(-180deg);
}

总的来说,您的代码可能比较干燥。寻找相似元素的共享样式并将它们组合在一起以避免不必要的麻烦。我在代码示例中留下了一些优化方法,但是例如您可以看到 .front-face-transition-exit-done.front-face-transition-enter 具有相同的规则,将它们放在一起!

祝CSS过渡顺利,如果您有任何问题,请告诉我。