【问题标题】:Material-UI Theme Overrides Leveraging Theme Palette ColorsMaterial-UI 主题覆盖利用主题调色板颜色
【发布时间】:2019-12-29 01:15:30
【问题描述】:

我目前正在使用全局主题覆盖自定义一些组件,希望尽可能多地保持 Material-UI 主题引擎的完整性。我知道我可以使用合成来完成我想做的事情,但我想看看是否可以通过覆盖来实现。

目标

更改 BottomNavigation 组件的背景颜色以使用当前主题的原色,并确保标签在该背景颜色之上获得清晰易读的颜色。

我目前的方法

const theme = createMuiTheme({
    palette: {
      primary: {
        main: 'rgba(217,102,102,1)'
      }
    },
    overrides: {
        MuiBottomNavigation: {
            root: {
                backgroundColor: 'rgba(217,102,102,1)'
            }
        },
        MuiBottomNavigationAction: {
            wrapper: {
                color: '#fff'
            }
        }
    }
});

此代码完成任务并将底部导航变为红色并将标签/图标变为白色。但是,我希望能够灵活地更改调色板中的原色并相应地更新组件。

我想做的事

const theme = createMuiTheme({
    palette: {
      primary: {
        main: 'rgba(217,102,102,1)'
      }
    },
    overrides: {
        MuiBottomNavigation: {
            root: {
                backgroundColor: 'primary.main'
            }
        },
        MuiBottomNavigationAction: {
            wrapper: {
                color: 'primary.contrastText'
            }
        }
    }
});

通过这种方式,我可以轻松地更新原色,而不必担心在我的覆盖中更改对它的每个引用。我意识到我可以将rgba 值提取到const 中,这将实现我的部分目标,但我不知道如何访问像contrastText 这样有用的东西,以防我选择更轻的主颜色。

那么 - 有没有人知道在主题覆盖定义中引用主题调色板颜色的方法?任何帮助将不胜感激!

【问题讨论】:

    标签: reactjs material-ui


    【解决方案1】:

    这里还有另一种方法。 createMuiThemeaccepts any number of additional theme objects to be merged together.

    考虑到这一点,您可以复制 your accepted answer 而无需两个不同的 ThemeProvider。如果您将主题定义移动到其自己的模块中,则不会在每次渲染时重新创建它。

    import { createMuiTheme } from "@material-ui/core/styles";
    
    const globalTheme = createMuiTheme({
      palette: {
        primary: {
          main: "rgba(217,255,102,1)"
        }
      }
    });
    
    const theme = createMuiTheme(
      {
        overrides: {
          MuiButton: {
            root: {
              backgroundColor: globalTheme.palette.primary.main
            },
            label: {
              color: globalTheme.palette.primary.contrastText
            }
          }
        }
      },
      globalTheme
    );
    
    export default theme;
    

    我更新了CodeSandBox 以反映这一点。

    【讨论】:

    • 这是我的首选解决方案
    • 不应该是...globalTheme吗?
    【解决方案2】:

    我将提供两种解决方案-一种更具可读性和可维护性,一种具有更好的性能。

    1. 可读且可维护的方法:
      创建嵌套主题。
      一个主题用于定义调色板,一个主题用于覆盖。
      因为它有两个主题,所以您可以从覆盖主题访问调色板主题:

      const globalTheme = createMuiTheme({
        palette: {
          primary: {
            main: 'rgba(217,255,102,1)'
          }
        },
      });
      
      const overridesTheme = createMuiTheme({
        overrides: {
          MuiButton: {
              root: {
                  backgroundColor: globalTheme.palette.primary.main,
              },
              label: {
                color:globalTheme.palette.primary.contrastText,
              }
          },
      }
      })
      

      你可以参考这个CodeSandbox

      这种方法性能不好,因为每次渲染都会计算并注入一个新的 CSS 对象


    1. 更好的性能方法:
      首先,您使用调色板创建一个 Mui 主题骨架。 创建后,添加依赖于调色板的样式(注意我必须大量使用扩展运算符以避免删除样式):

      const theme = createMuiTheme({
        palette: {
          primary: {
            main: 'rgba(217,255,102,1)'
          }
        },
      })
      
      theme.overrides = {
        ...theme.overrides,
        MuiButton: {
            ...theme.MuiButton,
            root: {
               ...theme.root,
                backgroundColor: theme.palette.primary.main,
            },
            label: {
              ...theme.label,
              color:theme.palette.primary.contrastText,
            }
        },
      }
      

      你可以参考这个CodeSandbox

    【讨论】:

    • 谢谢!我不敢相信我没有想到在创建主题对象后只编辑它......同时学习 React 和 MUI 有时肯定会令人困惑。我实施了第二个选项,并且效果很好。不过,我很想了解一点 - 您能否详细说明为什么第一个解决方案会导致计算/注入新的 CSS 对象而第二个解决方案不会?
    • 是的。注入的 css 与主题一起缓存。如果您在每次渲染时提供一个新主题,则缓存不再有效,因此将计算并注入一个新的 CSS 对象。通过嵌套主题,您可以做到这一点——每次渲染都提供一个新主题。
    • 您始终可以使用useMemo 来确保不会重新创建主题 - 我目前这样做是因为可以根据用户对暗/亮模式的偏好重新创建我的主题。关于第一个选项的问题 - overridesTheme 是否继承自 globalTheme?即overridesTheme 上的调色板是否包含修改后的原色?还是只会在覆盖中引用它?
    • @n-devr 对此有更好的方法。请参阅下面的新答案。
    【解决方案3】:

    适用于查看此主题并在主题之间切换的答案的人。

    https://codesandbox.io/s/material-theme-switching-with-pallete-colors-vfdhn

    创建两个 Theme 对象并在它们之间切换。在它们之间使用相同的主题属性,这样您的所有覆盖都可以使用相同的调色板,以确保不会重复,我们完全使用覆盖。

    import { createMuiTheme } from "@material-ui/core/styles";
    
    let globalTheme = createMuiTheme({
      palette: {
        primary: {
          main: "#fa4616"
        }
      }
    });
    
    export const LightTheme = createMuiTheme(
      {
        overrides: {
          MuiButton: {
            root: {
              backgroundColor: globalTheme.palette.primary.main
            },
            label: {
              color: globalTheme.palette.primary.contrastText
            }
          }
        }
      },
      globalTheme
    );
    
    globalTheme = createMuiTheme({
      palette: {
        primary: {
          main: "#0067df"
        }
      }
    });
    
    export const DarkTheme = createMuiTheme(
      {
        overrides: {
          MuiButton: {
            root: {
              backgroundColor: globalTheme.palette.primary.main
            },
            label: {
              color: globalTheme.palette.primary.contrastText
            }
          }
        }
      },
      globalTheme
    );
    

    【讨论】:

    • 我正在尝试自定义浅色/深色主题,虽然这更接近我的目标,但在顶层交换整个主题似乎放弃了 MUI 的内置 palette.mode 切换。在此 here 上发布了单独的 SO
    猜你喜欢
    • 2022-01-15
    • 2019-03-14
    • 1970-01-01
    • 2021-12-06
    • 1970-01-01
    • 2021-04-08
    • 1970-01-01
    • 2023-01-03
    • 1970-01-01
    相关资源
    最近更新 更多