无法在 withStyles HOC 中声明关键帧(container.addRule(...).addRule 不是函数)

Can't declare keyframe within withStyles HOC (container.addRule(...).addRule is not a function)

所以我得到了最新版本的jss和materialui。 我在样式对象中使用 withStyles HOC 并动态更改 css,但我似乎无法在 css 中声明关键帧。如果有任何不同,我也使用 nextjs。我看过 material-ui 是如何声明他们的动画的,我正在按照他们的例子 https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/ButtonBase/TouchRipple.js.

import React, { useEffect, useState } from "react";
import classnames from "classnames";
import PropTypes from "prop-types";
import { withStyles, makeStyles } from "@material-ui/core/styles";
import { sectionAnchors, maxContentWidth } from "../../../util/constants";
import LearnMoreLink from "./LearnMoreLink";
import SectionContent from "../../common/SectionContent";
import content from "../../../../content";
import useRealHeight from "../../../util/useRealHeight";
import SplashHeading from "./SplashHeading";

import { singleHeight, doubleHeight } from "../../common/Footer";
import GetStartedForm from "./GetStartedForm";
import { withRouter } from "next/router";
import SwipeableTextMobileStepper from "./SwipeableTextMobileStepper";
import { Link } from 'next/router'

import Radio from '@material-ui/core/Radio';
import RadioGroup from '@material-ui/core/RadioGroup';
import FormHelperText from '@material-ui/core/FormHelperText';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormControl from '@material-ui/core/FormControl';
import FormLabel from '@material-ui/core/FormLabel';
import { green } from '@material-ui/core/colors';
import RadioButtonUncheckedIcon from '@material-ui/icons/RadioButtonUnchecked';
import RadioButtonCheckedIcon from '@material-ui/icons/RadioButtonChecked';
import Switch from '@material-ui/core/Switch';
import Button from '@material-ui/core/Button';

const styles = theme => ({
    heading: {
        marginBottom: theme.spacing.unit * 6
    },
    headingColored: {
        marginBottom: 0,
        color: theme.palette.primary.dark
    },
    container: {
        width: "100%",
        //         '@keyframes fade': {
        //             '0%': {
        //              opacity: 1
        //             },
        //             '100%': {
        //              opacity: 0
        //          }
        //         },
        '@keyframes enter': {
            '0%': {
                transform: 'scale(0)',
                opacity: 0.1,
            },
            '100%': {
                transform: 'scale(1)',
                opacity: 0.3,
            },
        },
        // backgroundColor: theme.palette.primary.dark,
        // background: 'url(https://images.newscientist.com/wp-content/uploads/2019/04/08111018/screenshot-2019-04-08-10.24.34.jpg)',
        backgroundImage: props => props.background,
        backgroundSize: "cover",
        // animation: '$fadeMe linear 1s infinite',
        // animationName: '@fadeMe',
        // animdationDuration: '1s',
        // animation:
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center"
    },
    containerWizard: {
        background: "none",
        marginBottom: -doubleHeight,
        paddingBottom: doubleHeight + theme.spacing.unit * 3,
        [theme.breakpoints.up("sm")]: {
            marginBottom: -singleHeight,
            paddingBottom: singleHeight + theme.spacing.unit * 3
        }
    },
    inner: {
        maxWidth: maxContentWidth,
        width: "100%",
        flex: "1 0 auto",

        display: "flex",
        flexDirection: "column",
        justifyContent: "center",
        alignItems: "center"
    },
    flex: {
        flex: "1 0 auto"
    },
    form: {
        width: "100%",
        maxWidth: maxContentWidth / 2,

        display: "flex",
        flexDirection: "column",
        justifyContent: "center",
        alignItems: "center"
    }
});
// http://www.coverbash.com/wp-content/covers/caeli_flowers_facebook_cover.jpg

function SplashLogic() {
    const [selectedValue, setSelectedValue] = React.useState(1);
    let int
    useEffect(() => { int = init(1) }, []);
    let background = selectedValue == 1 ? bG('http://www.coverbash.com/wp-content/covers/caeli_flowers_facebook_cover.jpg') :
        bG('https://images.newscientist.com/wp-content/uploads/2019/04/08111018/screenshot-2019-04-08-10.24.34.jpg?')

    const handleChange = event => {
        setSelectedValue(event.target.value);
        clearInterval(int)
        int = init(event.target.value)
    };

    function init(num) {
        return setInterval(() => {
            background = bG('http://www.coverbash.com/wp-content/covers/caeli_flowers_facebook_cover.jpg')
            setSelectedValue(2)

        }, 4000)
    }

    return <SplashFull {...{ setSelectedValue, selectedValue, background, handleChange }}></SplashFull>
}

const SplashSection = ({ classes, router, setSelectedValue, selectedValue, background, handleChange }) => {
    // const [height] = useRealHeight({ resize: false });
    console.log(classes.container)
    useEffect(() => {
        router.prefetch("/signup");
    }, []);

    const onSubmit = values => {
        router.push(`/signup?destination=${values.destination}`, "/signup");
    };

    return (
        <SectionContent id={sectionAnchors.SPLASH} className={classes.container}>
            <div className="bg-white opacity-50 rounded-full">
                <Radio
                    checked={selectedValue === 1}
                    onChange={handleChange}
                    value={1}
                    name="radio-button-demo"
                    inputProps={{ 'aria-label': 'A' }}
                />
                <Radio
                    checked={selectedValue === 2}
                    onChange={handleChange}
                    value={2}
                    name="radio-button-demo"
                    inputProps={{ 'aria-label': 'B' }}
                />
                <Radio
                    checked={selectedValue === 3}
                    onChange={handleChange}
                    value={3}
                    name="radio-button-demo"
                    inputProps={{ 'aria-label': 'D' }}
                />
                <Radio
                    checked={selectedValue === 4}
                    onChange={handleChange}
                    value={4}
                    name="radio-button-demo"
                    inputProps={{ 'aria-label': 'E' }}
                />
            </div>
            <div className={classes.inner}>
                <SplashHeading
                    classes={{
                        container: classes.heading
                    }}
                />
                <GetStartedForm className={classes.form} onSubmit={onSubmit} />
            </div>
            <Button variant="contained" >
                Default
      </Button>
            <LearnMoreLink />
        </SectionContent>
        // <SwipeableTextMobileStepper></SwipeableTextMobileStepper>
    );
};

SplashSection.propTypes = {
    classes: PropTypes.object.isRequired
};

function bG(arg) {
    return `url(${arg})`
}

const SplashFull = withStyles(styles)(withRouter(SplashSection));

export default SplashLogic

我收到错误:

container.addRule(...).addRule is not a function

TypeError: container.addRule(...).addRule is not a function
    at Array.onProcessStyle (/workspace/travelcontacts/node_modules/jss-plugin-nested/dist/jss-plugin-nested.cjs.js:96:10)
    at PluginsRegistry.onProcessStyle (/workspace/travelcontacts/node_modules/jss/dist/jss.cjs.js:1246:51)
    at PluginsRegistry.onProcessRule (/workspace/travelcontacts/node_modules/jss/dist/jss.cjs.js:1235:26)
    at Array.forEach (<anonymous>)
    at RuleList.process (/workspace/travelcontacts/node_modules/jss/dist/jss.cjs.js:871:25)
    at new StyleSheet (/workspace/travelcontacts/node_modules/jss/dist/jss.cjs.js:1041:16)
    at Jss.createStyleSheet (/workspace/travelcontacts/node_modules/jss/dist/jss.cjs.js:2007:17)
    at attach (/workspace/travelcontacts/node_modules/@material-ui/styles/makeStyles/makeStyles.js:116:39)
    at /workspace/travelcontacts/node_modules/@material-ui/styles/makeStyles/makeStyles.js:256:7
    at useSynchronousEffect (/workspace/travelcontacts/node_modules/@material-ui/styles/makeStyles/makeStyles.js:210:14)
    at /workspace/travelcontacts/node_modules/@material-ui/styles/makeStyles/makeStyles.js:248:5
    at Object.WithStyles [as render] (/workspace/travelcontacts/node_modules/@material-ui/styles/withStyles/withStyles.js:70:21)
    at ReactDOMServerRenderer.render (/workspace/travelcontacts/node_modules/react-dom/cjs/react-dom-server.node.development.js:3758:44)
    at ReactDOMServerRenderer.read (/workspace/travelcontacts/node_modules/react-dom/cjs/react-dom-server.node.development.js:3538:29)
    at renderToString (/workspace/travelcontacts/node_modules/react-dom/cjs/react-dom-server.node.development.js:4247:27)
    at render (/workspace/travelcontacts/node_modules/next-server/dist/server/render.js:86:16)

问题似乎已通过不嵌套 @keyframes 定义得到解决。提示是在错误的addRule函数的第二次应用中:container.addRule(...).addRule is not a function.

解决方案

尝试将关键帧动画移动到根级别。所以从这个

const styles = theme => ({
  container: {
    '@keyframes enter': {
      '0%': {
        transform: 'scale(0)',
        opacity: 0.1,
      },
      '100%': {
        transform: 'scale(1)',
        opacity: 0.3,
      },
    }
  }
}

至此

const styles = theme => ({
  '@keyframes enter': {
      '0%': {
          transform: 'scale(0)',
          opacity: 0.1,
      },
      '100%': {
          transform: 'scale(1)',
          opacity: 0.3,
      },
  }
}

希望对您有所帮助。


有趣的旁注: 嵌套动画 另一个 级别消除了错误,但没有实例化 CSS 动画。

来自

const styles = theme => ({
  container: {
    '@keyframes enter': {
      '0%': {
        transform: 'scale(0)',
        opacity: 0.1,
      },
      '100%': {
        transform: 'scale(1)',
        opacity: 0.3,
      },
    }
  }
}

const styles = theme => ({
'@global':{ //need add into global rules
  '@keyframes enter': {
      '0%': {
          transform: 'scale(0)',
          opacity: 0.1,
      },
      '100%': {
          transform: 'scale(1)',
          opacity: 0.3,
      },
   }
 }
}