【问题标题】:MUI customize button color?MUI自定义按钮颜色?
【发布时间】:2017-09-29 10:07:48
【问题描述】:

我正在努力修改 MUI next (v1) 中的按钮颜色。

我如何设置 muitheme 以表现与引导程序的相似性,所以我可以只使用红色的“btn-danger”,绿色的“btn-success”...?

我尝试使用自定义className,但它不能正常工作(悬停颜色不会改变)并且看起来重复。我有什么选择?

【问题讨论】:

    标签: javascript reactjs material-ui


    【解决方案1】:

    你可以试试这个

    <Button
        style={{
            borderRadius: 35,
            backgroundColor: "#21b6ae",
            padding: "18px 36px",
            fontSize: "18px"
        }}
        variant="contained"
        >
        Submit
    </Button>
    

    【讨论】:

    • 内联样式是一个 hacky 解决方案
    【解决方案2】:

    我在这个线程中使用 Brendan 的答案提出了这个解决方案。希望它能帮助处于类似情况的人。

    import React, { Component } from 'react'
    import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles'
    import Button from 'material-ui/Button'
    import { red, blue } from 'material-ui/colors'
    
    const redTheme = createMuiTheme({ palette: { primary: red } })
    const blueTheme = createMuiTheme({ palette: { primary: blue } })
    
    class Buttons extends Component {
      render = () => (
        <div className="ledger-actions-module">
          <MuiThemeProvider theme={redTheme}>
            <Button color="primary" variant="raised">
              Delete
            </Button>
          </MuiThemeProvider>
          <MuiThemeProvider theme={blueTheme}>
            <Button color="primary" variant="raised">
              Update
            </Button>
          </MuiThemeProvider>
        </div>
      )
    }
    

    【讨论】:

    • 适用于 v4 import { ThemeProvider } from '@material-ui/styles'; import { createMuiTheme } from "@material-ui/core/styles";
    • 这是一种解决方法,而不是真正的解决方案。我们应该能够使用简单的主题配置创建自定义按钮。
    • 关于性能的警告 -> 如果您有一个包含 n 个项目的列表,每个项目都需要红色和蓝色按钮,该怎么办?这将需要 n * 2 个主题提供程序,并且最终可能会使浏览器崩溃。也不是对开发人员非常友好,因为这需要大量样板代码来设置颜色。我在下面发布了一个可能的解决方案,允许&lt;Button color="error"&gt; 等。
    【解决方案3】:

    Bagelfp 的回答有误,还有一些需要考虑的事情;

    首先,material-ui@next v1 的 Button component 中不支持“错误”颜色主题。 color 属性只接受 'default'、'inherit'、'primary' 和 'secondary'。

    这是迄今为止我发现的最简单的方法。首先,选择您最常用的两种主题颜色并将它们放在应用的根目录中。

    import React from 'react';
    import { Component } from './Component.js'
    import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
    
    const theme = createMuiTheme({
      palette: {
        primary: 'purple',
        secondary: 'green',
        error: 'red',
      },
    });
    
    export class App extends Component {
      render() {
        return (
          <MuiThemeProvider theme={theme}>
            <Component />
            ...
          </MuiThemeProvider>
        );
      }
    }
    

    然后在你的组件中,选择你想要的颜色的主题;

    import React from 'react';
    import Button from 'material-ui/Button';
    
    export const Component = (props) => (
      <div>
        <Button variant="fab" color="primary">
          I am purple, click me!
        </Button>
      </div>
    )
    

    如果您需要第三种和第四种颜色,您可以像在 App.js 中一样使用新的调色板导出 Component.js。

    这是我发现的唯一解决方案,可以让我保留变暗的悬停效果(official override examples 都没有保留功能悬停)。我真的希望我能找到一种在调用 Button 时简单地放入新主题颜色的方法,但目前这是最简单的方法。

    编辑:我的新首选方法是使用 styled-components 和 material-ui buttonbase 创建一个 CustomButton 组件。我还将 styled-components 主题提供程序与我的 MuiThemeProvider 放在我的应用程序的根目录中。这使我可以轻松访问所有样式组件中的其他主题颜色,而无需导入和放入更多 ThemeProviders。对于我的 CustomButton,我只是给它一个 theme 属性,它会直接传递给 styled(ButtonBase) 中的 css。有关详细信息,请参阅 styled-component 文档。

    【讨论】:

    • 有什么方法可以让它与 #17a2b8 等自定义颜色代码一起使用?
    • 是的,只需输入 HEX 或 RGBA 作为调色板对象的一部分(我在其中写了紫色、绿色、红色)。
    • 主题定义还允许maindarklight等变体——如默认主题material-ui.com/customization/default-theme所示有没有办法将颜色设置为@987654331 @变种?
    • @timbo 深色和浅色变体可以设置如下: const theme = createMuiTheme({ palette: { error: { main: '#e9f0f3', dark: '#c9d9e0', light: '# ffff00' } }, });
    • 你能展示一下你解释的最后一种方法吗? (在最后的“编辑:”)
    【解决方案4】:

    试试这个:

    import * as React from 'react';
    import Button, { ButtonProps } from "@material-ui/core/Button";
    import { Theme } from '@material-ui/core';
    import { withStyles } from '@material-ui/styles';
    
    const styles: (theme: Theme) => any = (theme) => {
        return {
            root:{
                backgroundColor: theme.palette.error.main,
                color: theme.palette.error.contrastText,
                "&:hover":{
                    backgroundColor: theme.palette.error.dark
                },
                "&:disabled":{
                    backgroundColor: theme.palette.error.light
                }
            }
        };
    };
    
    export const ButtonContainedError = withStyles(styles)((props: ButtonProps) => {
        const { className, ...rest } = props;
        const classes = props.classes||{};
        return <Button {...props} className={`${className} ${classes.root}`} variant="contained" />
    });
    

    现在您可以在任何地方使用 ButtonContainedError。

    而且和你的主题一致。

    【讨论】:

    • 这样做的好处是,如果在您的主题中您只指定了main 颜色,那么似乎可以正确计算暗属性和亮属性。前任。粉红色的main 值将导致深色和浅色分别为深粉色和浅粉色。
    【解决方案5】:

    这是一个示例打字稿实现:

    import React from "react";
    import { createStyles, Theme, makeStyles } from "@material-ui/core/styles";
    import capitalize from "lodash/capitalize";
    
    import MuiButton, {
      ButtonProps as MuiButtonProps
    } from "@material-ui/core/Button";
    
    export type ColorTypes =
      | "primary"
      | "secondary"
      | "error"
      | "success"
      | "warning"
      | "default"
      | "inherit"
      | "info";
    
    type ButtonProps = { color: ColorTypes } & Omit<MuiButtonProps, "color">;
    
    const useStyles = makeStyles<Theme>(theme =>
      createStyles({
        outlinedSuccess: {
          borderColor: theme.palette.success.main,
          color: theme.palette.success.main
        },
        outlinedError: {
          borderColor: theme.palette.error.main,
          color: theme.palette.error.main
        },
        outlinedWarning: {
          borderColor: theme.palette.warning.main,
          color: theme.palette.warning.main
        },
        outlinedInfo: {
          borderColor: theme.palette.info.main,
          color: theme.palette.info.main
        },
        containedSuccess: {
          backgroundColor: theme.palette.success.main,
          color: theme.palette.success.contrastText,
          "&:hover": {
            backgroundColor: theme.palette.success.dark
          }
        },
        containedError: {
          backgroundColor: theme.palette.error.main,
          color: theme.palette.error.contrastText,
          "&:hover": {
            backgroundColor: theme.palette.error.dark
          }
        },
        containedWarning: {
          backgroundColor: theme.palette.warning.main,
          color: theme.palette.warning.contrastText,
          "&:hover": {
            backgroundColor: theme.palette.warning.dark
          }
        },
        containedInfo: {
          backgroundColor: theme.palette.info.main,
          color: theme.palette.info.contrastText,
          "&:hover": {
            backgroundColor: theme.palette.info.dark
          }
        }
      })
    );
    
    const Button: React.FC<ButtonProps> = ({ children, color, ...props }) => {
      const classes = useStyles();
      const className = classes?.[`${props.variant}${capitalize(color)}`];
      const colorProp =
        ["default", "inherit", "primary", "secondary"].indexOf(color) > -1
          ? (color as "default" | "inherit" | "primary" | "secondary")
          : undefined;
    
      return (
        <MuiButton {...props} color={colorProp} className={className}>
          {children}
        </MuiButton>
      );
    };
    
    Button.displayName = "Button";
    
    export default Button;
    
    

    有了这个,你可以做到&lt;Button variant="contained" color="success"&gt; 自动完成和无警告:)

    更新:

    Material UI V5 中,这可以通过更优雅的方式实现。您只需向调色板添加颜色,按钮就会自动支持它!他们的文档有一个很好的例子来说明如何做到这一点:https://mui.com/customization/palette/#adding-new-colors

    【讨论】:

    • 不错的解决方案? Typescript 4.0.3 似乎不喜欢这一行:const className = classes?.[`${props.variant}${capitalize(color)}`];Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Record&lt;"root" | "textError" | "outlinedError" | "containedError", string&gt;'.
    • 我使用了这种方法。我为解决您提到的@Bassem 的 ts 错误所做的事情是,classes[`${variant}${capitalize(color)}` as keyof typeof classes] 注意as keyof typeof classes。虽然我不确定我的队友是否会接受它,tbh。我很快就会对我的 PR 进行审核。
    • 不错的 hack @PenguinBlues ?,如果您的队友有其他想法,请随时更新,我将取消 @ts-ignore 的注释并暂时使用您的解决方案
    • 他们接受了@Bassem,所以一定没问题,呵呵
    • 谢谢@PenguinBlues ?
    【解决方案6】:

    您可以使用theme.palette.getContrastText() 根据背景颜色值计算正确的文本颜色。

    import { Button, makeStyles } from '@material-ui/core';
    
    const useStyles = makeStyles((theme) => ({
      deleteButton: {
        // to make a red delete button
        color: theme.palette.getContrastText(theme.palette.error.main),
        background: theme.palette.error.main,
      }
    }));
    
    export const DeleteButton = () => {
      const classes = useStyles();
      return (
        <Button className={classes.deleteButton}>Delete</Button>
      );
    }
    

    【讨论】:

      【解决方案7】:

      MUI v5 中,这是您在主题中为您的 MUI Button 创建自定义颜色的方式。 primary and secondary colors 的创建方式与 under the hood 相同:

      const { palette } = createTheme();
      const { augmentColor } = palette;
      const createColor = (mainColor) => augmentColor({ color: { main: mainColor } });
      const theme = createTheme({
        palette: {
          anger: createColor('#F40B27'),
          apple: createColor('#5DBA40'),
          steelBlue: createColor('#5C76B7'),
          violet: createColor('#BC00A3'),
        },
      });
      

      用法

      <Button color="anger" variant="contained">
        anger
      </Button>
      <Button color="apple" variant="contained">
        apple
      </Button>
      <Button color="steelBlue" variant="contained">
        steelBlue
      </Button>
      <Button color="violet" variant="contained">
        violet
      </Button>
      

      如果您使用的是 typescript,您还需要为刚刚定义的颜色添加其他类型:

      declare module '@mui/material/styles' {
        interface CustomPalette {
          anger: PaletteColorOptions;
          apple: PaletteColorOptions;
          steelBlue: PaletteColorOptions;
          violet: PaletteColorOptions;
        }
        interface Palette extends CustomPalette {}
        interface PaletteOptions extends CustomPalette {}
      }
      
      declare module '@mui/material/Button' {
        interface ButtonPropsColorOverrides {
          anger: true;
          apple: true;
          steelBlue: true;
          violet: true;
        }
      }
      

      现场演示

      相关答案

      【讨论】:

        【解决方案8】:

        首先尝试安装 npm install @material-ui/styles 根据材料文档应用样式,对于反应类组件,您可以使用以下代码:

        import React, {Component} from "react";
        import { styled } from '@material-ui/styles';
        import Button from '@material-ui/core/Button';
        
        const MyButton = styled(Button)({
            background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
            border: 0,
            borderRadius: 3,
            boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
            color: 'white',
            height: 48,
            padding: '0 30px',
        });
        class AprinClass extends Component {
            render() {
                return (
                    <MyButton>Styled Components</MyButton>
                )
            }
        }
        export default AprinClass;
        

        有关参考的更多信息,请查看我的中等博客。 https://medium.com/@farbodaprin/how-to-make-a-customisable-material-ui-button-a85b6534afe5

        【讨论】:

        • 你可以把你的颜色代替次要和主要!
        【解决方案9】:

        您可以创建一个 theme,并为其 3 个受支持的 intentions(主要、次要、错误)中的每一个定义调色板,然后使用 &lt;Button&gt; 上的 color 属性来使用它们。 在您的示例中,btn-danger 可能是 &lt;Button color='error'&gt;

        编辑: Brendan 的回答是正确的,Button 不支持 error。根据文档,Button 只支持“对这个组件有意义”的意图。所以只有 primarysecondary 可以在这里工作。

        来自their docs(此处略减):

        const theme = createMuiTheme({
          palette: {
            primary: purple,
            secondary: red
          }
        });
        
        function Palette() {
          return (
            <MuiThemeProvider theme={theme}>
              <div>
                <Button color="primary">{'Primary'}</Button>
                <Button color="secondary">{'Secondary'}</Button>
              </div>
            </MuiThemeProvider>
          );
        }
        

        请参阅Brendan's Answer,了解为您的组件创建主题的更真实示例。

        【讨论】:

          【解决方案10】:

          我发现 !important 在课程中有效。 (反应钩子)

          const styles "...etc..." = (theme: Theme) => ({
              buttonWarning: {
                  backgroundColor: theme.palette.warning.dark + '!important'
              }
          }))
          

          然后在按钮中

          const classes = styles();
          
          <Button className={classes.buttonWarning}>Hello</Button>
          

          【讨论】:

            【解决方案11】:

            更改按钮颜色的最简单方法是添加“样式”属性。这是我创建的绿色按钮的示例:

            import Button from '@material-ui/core/Button';
            
              <Button 
                variant="contained" 
                color="primary" 
                style={{ backgroundColor: '#357a38' }}
              >
                Run
              </Button>
            

            【讨论】:

            • 欢迎来到 SO。尽管我们感谢您的回答,但如果它在其他答案之上提供额外的价值会更好。在这种情况下,您的答案不会提供额外的价值,因为 Adnan shah 已经发布了该解决方案。如果之前的回答对您有帮助,请在您有足够的reputation 时使用vote it up
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-12-20
            • 1970-01-01
            • 2023-01-19
            • 2018-07-05
            • 2019-12-09
            • 2015-10-18
            • 1970-01-01
            相关资源
            最近更新 更多