如何在 MUI 中应用自定义动画效果@关键帧?

我已经学会在 CSS 中使用动画使用 @keyframe。然而,我想写我的自定义动画代码到我的反应项目(使用 MUI)。我的挑战是如何使用 MUI 中的 makeStyle()编写 Javascript 代码来定制我的动画。

我希望能够自定义转换过程的百分比 这次是在 MUI。我需要能够在 makeStyle()编写这样的代码,但我似乎不知道如何。

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


100% {
opacity:1;
transform: translateY(0);
}
}
61997 次浏览

Here is an example demonstrating the keyframes syntax within makeStyles:

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);

Edit keyframes

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


For those who have started using Material-UI v5 and want to know how to do this using Emotion rather than makeStyles, below is an example of one way to do the equivalent styles using 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);

Edit keyframes emotion

Emotion keyframes documentation: https://emotion.sh/docs/keyframes

V5

In v5, you can use the keyframes function (which is re-exported from emotion by default) to generate the stylesheet for keyframe:

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`
});

Because both styled/sx prop use emotion internally, you can pass the same style object to the sx prop:

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

Codesandbox Demo

V4

Just some notes on top of @Ryan's answer. If you define the keyframe using makeStyles. Remember to prefix the animation name with $. I missed this small detail the first time and my code didn't work, in the example below

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

Instead of

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

It should be

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

But if you define the keyframe in global scope. The prefix is unnecessary here

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
}
});

Follow this issue on github for more discussion about this.