【问题标题】:Material-UI NextJS Button Styling IssueMaterial-UI NextJS 按钮样式问题
【发布时间】:2022-02-12 01:35:31
【问题描述】:

我在 JS 中的几个按钮上正确设置样式时遇到问题,似乎当我通过 className 添加一个样式类时,它在第一次呈现格式化工作时,但在随后的刷新时它失去了它的样式。它只发生在我拥有的两个单独的按钮上。经过多年的故障排除后,我发现当我使用 SX 而不是 classNames 时一切正常,所以如果我这样做,那么刷新工作。所以在下面的代码中,一个按钮样式和保持样式,但第二个,刷新我的按钮类没有?在这一点上被难住了,我浏览了论坛,看到很多关于 NextJs 需要在 _document 和 _app 中进行一些额外配置才能使其工作的信息,但是我从 Git 的 NextJs Material UI 样板中运行了这个,所以不认为这可能是导致它。

代码:

import React from 'react'

import { AppBar, Toolbar, alpha } from "@mui/material";
import Button from '@mui/material/Button'
import ButtonBase from '@mui/material/ButtonBase';
import { styled } from '@mui/material/styles';
import Typography from '@mui/material/Typography';
import InputBase from '@mui/material/InputBase';
import SearchIcon from '@mui/icons-material/Search';
import AddIcon from '@mui/icons-material/Add';
import { makeStyles } from '@mui/styles'

const useStyles = makeStyles(theme => ({

    button: {
        ...theme.typography.mainmenu,
        borderRadius: "40px",
        width: "230px",
        height: "130px",
        marginLeft: "30px",
        alignItem: "center",
        "&:hover": {
            backgroundColor: theme.palette.secondary
        },
        [theme.breakpoints.down("sm")]: {
            width: '100% !important', // Overrides inline-style
            height: 100
        },
    },

}))
/*Image Button Styling Begins*/
const images = [
    {
        url: '/assets/breakfastMenu.jpg',
        title: 'Breakfast',
        width: '20%',
    },
    {
        url: '/assets/steak.jpg',
        title: 'Mains',
        width: '20%',
    },
    {
        url: '/assets/desserts.jpg',
        title: 'Desserts',
        width: '20%',
    },
];
const Image = styled('span')(({ theme }) => ({
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    color: theme.palette.common.primary,
}));

const ImageButton = styled(ButtonBase)(({ theme }) => ({
    position: 'relative',
    height: 150,
    [theme.breakpoints.down('sm')]: {
        width: '100% !important', // Overrides inline-style
        height: 100,
    },
    '&:hover, &.Mui-focusVisible': {
        zIndex: 1,
        '& .MuiImageBackdrop-root': {
            opacity: 0.15,
        },
        '& .MuiImageMarked-root': {
            opacity: 0,
        },
        '& .MuiTypography-root': {
            border: '4px solid currentColor',
        },
    },
}));

const ImageSrc = styled('span')({
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    backgroundSize: 'cover',
    backgroundPosition: 'center 40%',
});
const ImageBackdrop = styled('span')(({ theme }) => ({
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    backgroundColor: theme.palette.common.black,
    opacity: 0.4,
    transition: theme.transitions.create('opacity'),
}));

const ImageMarked = styled('span')(({ theme }) => ({
    height: 3,
    width: 18,
    backgroundColor: theme.palette.common.white,
    position: 'absolute',
    bottom: -2,
    left: 'calc(50% - 9px)',
    transition: theme.transitions.create('opacity'),
}));
/*Image Button Styling Ends*/

const Search = styled('div')(({ theme }) => ({
    position: 'relative',
    borderRadius: theme.shape.borderRadius,
    backgroundColor: alpha(theme.palette.common.white, 0.15),
    '&:hover': {
        backgroundColor: alpha(theme.palette.common.white, 0.25),
    },
    marginLeft: 0,
    width: '100%',
    [theme.breakpoints.up('sm')]: {
        marginLeft: theme.spacing(1),
        width: 'auto',
    },
}));

const SearchIconWrapper = styled('div')(({ theme }) => ({
    padding: theme.spacing(0, 2),
    height: '100%',
    position: 'absolute',
    pointerEvents: 'none',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
}));

const StyledInputBase = styled(InputBase)(({ theme }) => ({
    color: 'inherit',
    '& .MuiInputBase-input': {
        padding: theme.spacing(1, 1, 1, 0),
        // vertical padding + font size from searchIcon
        paddingLeft: `calc(1em + ${theme.spacing(4)})`,
        transition: theme.transitions.create('width'),
        width: '100%',
        [theme.breakpoints.up('sm')]: {
            width: '12ch',
            '&:focus': {
                width: '20ch',
            },
        },
    },
}));


const Header = () => {
    const classes = useStyles();
    return (<React.Fragment>
        <AppBar position="sticky" className={classes.appBar}>
            <Toolbar disableGutters>

                {images.map((image) => (
                    <ImageButton
                        focusRipple
                        key={image.title}
                        style={{
                            width: image.width,
                        }}
                    >
                        <ImageSrc style={{
                            backgroundImage: `url(${image.url})`
                        }} />
                        <ImageBackdrop className="MuiImageBackdrop-root" />
                        <Image>
                            <Typography
                                component="span"
                                variant="subtitle1"
                                color="white"
                                fontWeight="bold"

                                sx={{
                                    position: 'relative',
                                    p: "7em",
                                    pt: "2em",
                                    pb: (theme) => `calc(${theme.spacing(1)} + 6px)`,
                                }}
                            >
                                {image.title}
                                <ImageMarked className="MuiImageMarked-root" />
                            </Typography>
                        </Image>
                    </ImageButton>
                ))}
                <Button size="large" variant="contained" color="secondary"
                    startIcon={<AddIcon />}
                    sx={{
                        borderRadius: "40px", borderRadius: "40px",
                        width: "230px",
                        height: "130px",
                        marginLeft: "30px",
                        alignItem: "center",
                    }} >Add A recipe</Button>
                <Button size="large" variant="contained" color="secondary" className={classes.button}>Meals for the Week</Button>
                <Search>
                    <SearchIconWrapper>
                        <SearchIcon />
                    </SearchIconWrapper>
                    <StyledInputBase
                        placeholder="Search…"
                        inputProps={{ 'aria-label': 'search' }}
                    />
                </Search>
            </Toolbar>
        </AppBar>

    </React.Fragment >
    )
}

export default Header

【问题讨论】:

    标签: html css reactjs material-ui next.js


    【解决方案1】:

    没错,您需要在_document.tsx 中添加一些配置,以使样式与NextJS 服务器端渲染功能正常工作。这背后的原因是您需要为您在 DOM 中注入一些样式。

    正如您在 MUI 文档中看到的,您可以使用 ServerStyleSheets 正确处理服务器端渲染。

    这是我在_document.tsx 中的代码

    import React from 'react';
    import Document, { Html, Main, NextScript } from 'next/document';
    import { ServerStyleSheets } from '@mui/styles';
    
    
    export default class MyDocument extends Document {
        render() {
            return (
                <Html>
                    <body>
                        <Main />
                        <NextScript />
                    </body>
                </Html>
            );
        }
    }
    
    MyDocument.getInitialProps = async (ctx) => {
        // Render app and page and get the context of the page with collected side effects.
        const sheets = new ServerStyleSheets();
        const originalRenderPage = ctx.renderPage;
    
        ctx.renderPage = () =>
            originalRenderPage({
                enhanceApp: (App) => (props) => sheets.collect(<App {...props} />)
            });
    
        const initialProps = await Document.getInitialProps(ctx);
    
        return {
            ...initialProps,
            // Styles fragment is rendered after the app and page rendering finish.
            styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()]
        };
    };
    

    您可以在这些Server rendering - MUI docs 中阅读有关此的更多信息

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-14
      • 2018-08-03
      • 2020-06-28
      • 2019-10-06
      • 2019-02-12
      • 2020-08-23
      • 2021-01-23
      • 2014-12-08
      相关资源
      最近更新 更多