【问题标题】:Implementing transition effects in React JS when state changes状态改变时在 React JS 中实现过渡效果
【发布时间】:2019-03-01 14:31:09
【问题描述】:

我在 React 页面上有一张图片。当状态更新为新图像时,我想执行以下过渡效果:

  • 原始图像应放大和淡出
  • 新图像也应该放大和淡入

效果应该类似于穿过墙壁进入新场景。

我如何在 React 中做到这一点?

【问题讨论】:

  • 给 react-pose 一个旋转popmotion.io/pose
  • 这更像是一个 CSS 问题。更改元素的 className,并使用 CSS 过渡对其进行动画处理
  • @Mikkel 好吧,除了 React 重新渲染页面时,旧图像消失了,新图像处于状态。所以,一个合适的解决方案应该是 React 和 CSS 的结合。可能与 componentWillUpdate 结合 CSS 有关,但事实证明它比我想象的要困难一些。
  • @azium 不确定这是否适合我。如果不需要,我宁愿不使用第三方库。另外,我似乎找不到任何关于它能够处理状态变化之间转换的信息。
  • 听起来你正在用新图像替换状态中的图像,导致 React 重新渲染并立即删除旧图像,因此会破坏任何随之而来的过渡。尝试在不删除旧图像的情况下将新图像添加到状态中,然后对两个图像进行动画处理,然后从状态中删除旧图像?

标签: javascript css reactjs css-transitions


【解决方案1】:

正如@pgsandstrom 所提到的,React Transition Group 是要走的路。不幸的是,它对开发人员不太友好(学习曲线相当陡峭)。

这是一个工作示例:https://codesandbox.io/s/6lmv669kz

✔ 原始图像在淡出时放大

✔ 新图像在淡入时放大

TransitionExample.js

import random from "lodash/random";
import React, { Component } from "react";
import { CSSTransition, TransitionGroup } from "react-transition-group";
import uuid from "uuid/v1";

const arr = [
  {
    id: uuid(),
    url: `https://loremflickr.com/600/100?lock=${random(0, 999)}`
  },
  {
    id: uuid(),
    url: `https://loremflickr.com/600/100?lock=${random(0, 999)}`
  },
  {
    id: uuid(),
    url: `https://loremflickr.com/600/100?lock=${random(0, 999)}`
  }
];

export default class TransitionExample extends Component {
  state = {
    index: 0,
    selected: arr[0]
  };

  nextImage = () =>
    this.setState(prevState => {
      const newIndex = prevState.index < arr.length - 1 ? prevState.index + 1 : 0;
      return {
        index: newIndex,
        selected: arr[newIndex]
      };
    });

  render = () => (
    <div className="app">
      <div style={{ marginBottom: 30, height: 100 }}>
        <TransitionGroup>
          <CSSTransition
            key={this.state.selected.id}
            timeout={1000}
            classNames="messageout"
          >
            <div style={{ marginTop: 20 }}>
              <img className="centered-image" src={this.state.selected.url} />
            </div>
          </CSSTransition>
        </TransitionGroup>
      </div>
      <div style={{ textAlign: "center" }}>
        <button
          className="uk-button uk-button-primary"
          onClick={this.nextImage}
        >
          Next Image
        </button>
      </div>
    </div>
  );
}

styles.css

.app {
  margin: 0 auto;
  overflow: hidden;
  width: 700px;
  height: 800px;
}

.centered-image {
  display: block;
  margin: 0 auto;
}

/* starting ENTER animation */
.messageout-enter {
  position: absolute;
  top: 0;
  left: calc(13% + 5px);
  right: calc(13% + 5px);
  opacity: 0.01;
  transform: translateY(0%) scale(0.01);
}

/* ending ENTER animation */
.messageout-enter-active {
  opacity: 1;
  transform: translateY(0%) scale(1);
  transition: all 1000ms ease-in-out;
}

/* starting EXIT animation */
.messageout-exit {
  opacity: 1;
  transform: scale(1.01);
}

/* ending EXIT animation */
.messageout-exit-active {
  opacity: 0;
  transform: scale(4);
  transition: all 1000ms ease-in-out;
}

【讨论】:

    【解决方案2】:

    这对我有用 (link):

    index.js:

    import React from "react";
    import { render } from "react-dom";
    
    import "./styles.scss";
    
    const src1 =
      "https://www.nba.com/dam/assets/121028030322-james-harden-traded-102712-home-t1.jpg";
    const src2 = "https://www.nba.com/rockets/sites/rockets/files/wcwebsite.jpg";
    
    var state = {
      toggle: true
    };
    
    class App extends React.Component {
      render() {
        const cn1 = "imgFrame " + (state.toggle ? "toggleOut" : "toggleIn");
        const cn2 = "imgFrame " + (state.toggle ? "toggleIn" : "toggleOut");
        return (
          <div>
            <img className={cn1} src={src1} alt={"img1"} />
            <img className={cn2} src={src2} alt={"img2"} />
            <button
              onClick={() => {
                state.toggle = !state.toggle;
                this.forceUpdate();
              }}
            >
              click me to toggle
            </button>
            <h1>Hello</h1>
          </div>
        );
      }
    }
    
    render(<App />, document.getElementById("app"));
    

    style.scss:

    html,
    body {
      background-color: papayawhip;
      font-family: sans-serif;
    
      h1 {
        color: tomato;
      }
    }
    
    @keyframes fadeout {
      0% {
        opacity: 1;
        transform: scale(1);
      }
      100% {
        opacity: 0;
        transform: scale(0.9);
      }
    }
    
    @keyframes fadein {
      0% {
        opacity: 0;
        transform: scale(1.1);
      }
      100% {
        opacity: 1;
        transform: scale(1);
      }
    }
    
    .toggleOut {
      animation: fadeout 500ms;
      opacity: 0;
    }
    
    .toggleIn {
      animation: fadein 500ms;
      opacity: 1;
    }
    
    .imgFrame {
      position: absolute;
      top: 10px;
      left: 10px;
      width: 200px;
      height: 200px;
    }
    
    button {
      position: absolute;
      top: 220px;
    }
    

    【讨论】:

    • 如果我有 3 张或多于 2 张图片,我该如何处理?
    【解决方案3】:

    听起来您正在寻找React Transition Group。这是解决这些问题的“官方”方式。具体来说,我认为this 是您应该使用的。掌握窍门可能有点棘手,但一旦你理解了它,它就会非常好用且功能强大。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-02-01
      • 1970-01-01
      • 2013-07-04
      • 2015-09-17
      • 2012-02-18
      • 1970-01-01
      • 1970-01-01
      • 2021-08-07
      相关资源
      最近更新 更多