如何在Material UI中应用自定义动画效果@keyframes?

102

我已经学会了如何使用@keyframe在CSS中制作动画。但是,我想为我的React项目(使用Material UI)编写自定义动画代码。我的挑战是如何使用makeStyle()在Javascript中编写自定义动画代码。

这一次,我想能够在Material UI中以百分比的方式自定义过渡效果。我需要能够像这样在makeStyle()中编写代码,但我似乎不知道该怎么做。

@keyframes myEffect {
 0%{
  opacity:0;
  transform: translateY(-200%); 
 }

100% {
  opacity:1;
  transform: translateY(0);
 }
}
2个回答

158

以下是一个示例,演示如何在 makeStyles内使用keyframes语法:

import React from "react";
import ReactDOM from "react-dom";

import { makeStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import clsx from "clsx";

const useStyles = makeStyles(theme => ({
  animatedItem: {
    animation: `$myEffect 3000ms ${theme.transitions.easing.easeInOut}`
  },
  animatedItemExiting: {
    animation: `$myEffectExit 3000ms ${theme.transitions.easing.easeInOut}`,
    opacity: 0,
    transform: "translateY(-200%)"
  },
  "@keyframes myEffect": {
    "0%": {
      opacity: 0,
      transform: "translateY(-200%)"
    },
    "100%": {
      opacity: 1,
      transform: "translateY(0)"
    }
  },
  "@keyframes myEffectExit": {
    "0%": {
      opacity: 1,
      transform: "translateY(0)"
    },
    "100%": {
      opacity: 0,
      transform: "translateY(-200%)"
    }
  }
}));

function App() {
  const classes = useStyles();
  const [exit, setExit] = React.useState(false);
  return (
    <>
      <div
        className={clsx(classes.animatedItem, {
          [classes.animatedItemExiting]: exit
        })}
      >
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
        <Button onClick={() => setExit(true)}>Click to exit</Button>
      </div>
      {exit && <Button onClick={() => setExit(false)}>Click to enter</Button>}
    </>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

编辑关键帧

文档:https://cssinjs.org/jss-syntax/?v=v10.0.0#keyframes-animation


对于那些开始使用Material-UI v5并想知道如何使用Emotion而不是makeStyles的人,下面是一个使用Emotion实现等效样式的示例。

/** @jsxImportSource @emotion/react */
import React from "react";
import ReactDOM from "react-dom";

import { css, keyframes } from "@emotion/react";
import { useTheme } from "@mui/material/styles";
import Button from "@mui/material/Button";

const myEffect = keyframes`
  0% {
    opacity: 0;
    transform: translateY(-200%);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
`;
const myEffectExit = keyframes`
  0% {
    opacity: 1;
    transform: translateY(0);
  }
  100% {
    opacity: 0;
    transform: translateY(-200%);
  }
`;

function App() {
  const theme = useTheme();
  const animatedItem = css`
    animation: ${myEffect} 3000ms ${theme.transitions.easing.easeInOut};
  `;
  const animatedItemExiting = css`
    animation: ${myEffectExit} 3000ms ${theme.transitions.easing.easeInOut};
    opacity: 0;
    transform: translateY(-200%);
  `;
  const [exit, setExit] = React.useState(false);
  return (
    <>
      <div css={exit ? animatedItemExiting : animatedItem}>
        <h1>Hello CodeSandbox</h1>
        <h2>Start editing to see some magic happen!</h2>
        <Button onClick={() => setExit(true)}>Click to exit</Button>
      </div>
      {exit && <Button onClick={() => setExit(false)}>Click to enter</Button>}
    </>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

编辑keyframes emotion

Emotion关键帧文档:https://emotion.sh/docs/keyframes


113

Material UI v5

在v5中,您可以使用keyframes函数(默认情况下从emotion重新导出)来生成关键帧的样式表:

import { styled } from '@mui/material/styles';
import { keyframes } from '@mui/system';

const spin = keyframes`
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
`;

const RotatedBox = styled("div")({
  backgroundColor: "pink",
  width: 30,
  height: 30,
  animation: `${spin} 1s infinite ease`
});

因为styled/sx属性都在内部使用emotion,所以可以将相同的样式对象传递给sx属性:

<Box
  sx={{
    backgroundColor: "pink",
    width: 30,
    height: 30,
    animation: `${spin} 1s infinite ease`
  }}
/>

Codesandbox Demo

Material UI v4

@Ryan's answer的基础上,这里有一些注意事项。如果你使用makeStyles定义keyframe,请记得在动画名称前加上$前缀。我第一次就错过了这个小细节,导致我的代码无法工作,下面是一个示例:

const useStyles = makeStyles({
  "@keyframes fadeIn": {
    "0%": {
      opacity: 0,
      transform: "translateY(5rem)"
    },
    "100%": {
      opacity: 1,
      transform: "translateY(0)"
    }
  },
  selector: {
    animation: "$fadeIn .2s ease-in-out"
  }
});

不是

animation: "fadeIn .2s ease-in-out"

应该是这样的

animation: "$fadeIn .2s ease-in-out"

但是如果你在全局作用域中定义了keyframe,这里就不需要前缀了。

const useStyles = makeStyles({
  "@global": {
    "@keyframes fadeIn": {
      "0%": {
        opacity: 0,
        transform: "translateY(5rem)"
      },
      "100%": {
        opacity: 1,
        transform: "translateY(0)"
      }
    }
  },
  selector: {
    animation: "fadeIn .2s ease-in-out" // --> this works
  }
});

请在 GitHub 上关注 issue 以获取更多关于此问题的讨论。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接