样式化组件的多个道具选项

Posted

技术标签:

【中文标题】样式化组件的多个道具选项【英文标题】:Multiple Props Options for Styled Components 【发布时间】:2019-09-26 14:17:49 【问题描述】:

我有一个使用样式化组件创建的导航栏组件。我想创建一些改变背景颜色和/或文本颜色的道具。

例如:<Navbar dark> 应具有以下 CSS:

background: #454545;
color: #fafafa;

<Navbar light> 应该相反:

background: #fafafa;
color: #454545;

但是,如果两个道具都没有使用,那么我想要一个默认的背景和文本颜色——比如说(出于演示目的),如下所示:

background: #eee;
color: #333;

现在,我的问题是如何在 Styled Components 中进行设置。

我可以做到以下几点:

background: $props => props.dark ? #454545 : '#eee'
background: $props => props.dark ? #fafafa : '#eee'
background:  #eee;

颜色也类似。

但这是多余的,不是很优雅。我想要某种 if/else 语句:

background: $ props =>  
  if (props.dark)  #454545 
  elseif (props.light)  #fafafa 
  else  #eee 

但我不知道如何在 Styled Components 中设置类似的内容。

有什么建议吗?

提前致谢。

【问题讨论】:

【参考方案1】:

保持传入的prop 名称相同。然后您可以使用switch/case 语句。例如,传入 color 属性并将其用作 type 以匹配 case

工作示例


例如:

<Button color="primary">Example</Button>

组件/按钮

import styled from "styled-components";

const handleColorType = color => 
  switch (color) 
    case "primary":
      return "#03a9f3";
    case "danger":
      return "#f56342";
    default:
      return "#fff";
  
;

const Button = styled.button`
  display: block;
  cursor: pointer;
  border: 0;
  margin: 5px 0;
  background: #000;
  font-size: 20px;
  color: $( color ) => handleColorType(color);

  &:focus 
    outline: 0;
  
`;

export default Button;

如果您有多个属性(例如 colorbackground 对),则使用与上述相同的概念,更改 handleColorType 以返回带有属性的 string 并调用 handleColorType 函数没有样式属性。

例如:

<MultiButton color="primary">Example</MultiButton>

组件/多按钮

import styled from "styled-components";

const handleColorType = color => 
  switch (color) 
    case "primary":
      return "color: #03a9f3; background: #000;";
    case "danger":
      return "color: #fff; background: #f56342;";
    default:
      return "color: #000; background: #eee;";
  
;

const MultiButton = styled.button`
  display: block;
  margin: 5px 0;
  cursor: pointer;
  border: 0;
  font-size: 20px;
  $( color ) => handleColorType(color);

  &:focus 
    outline: 0;
  
`;

export default MultiButton;

【讨论】:

这非常漂亮和优雅(我肯定有时会使用它)。但是,当我 想要将值传递给道具时,我也想要一个解决方案(例如我上面给出的深色和浅色示例)。我可以修改您的解决方案,使用 if/else 语句来检查是否设置了道具 - 即类似 if (props.dark) return 'background-color: #454545; color: #fafafa' elseif... 。这行得通吗? 或者,或者--是否可以将 switch 与道具一起使用,然后检查不同类型的道具。像这样的东西:switch (props) case props.dark...?我正在尝试使其正常工作,但出现错误。有什么想法吗? 如果所有情况都不匹配,switch/casedefault 会返回一些东西(或者可以是什么)。请参阅代码框示例。此外,再次保持相同的道具名称。在 props 中使用“dark”和“light”将迫使您使用重度嵌套的 if/else 语句。 但是,如果这是您绝对想要的,那么是的,您只需要添加一个 return 语句即可。 只是喜欢这种方法。一位前同事向我介绍了这一点,它比我使用的任何其他方法都优雅得多。【参考方案2】:

这是我最终使用的解决方案:

export const Navbar = styled.nav`
  width: 100%;

  ...  // rest of the regular CSS code

  $props => 
    if (props.dark) 
      return `
        background: $colors.dark;
        color: $colors.light;
    `
     else if (props.light) 
      return `
        background: $colors.light;
        color: $colors.dark;
    `
     else 
      return `
        background: $colors.light;
        color: $colors.dark;
    `
    
  
`

【讨论】:

这是我一直在寻找的。​​span> 【参考方案3】:

你也可以这样做:


 const colorType= 
   dark: '#454545',
   light: '#0a0a0a',
   normal: '#dedede'
;



export const Navbar= styled.nav`
   background: $(color) => colorType[color] || `$color`;

`;

你在这里:

<Navbar color="primary" />
<Navbar color="#FFFFFF" />

【讨论】:

【参考方案4】:

更优雅(我猜)和现代的东西是解构道具和使用 switch 语句的组合,例如:

const Button = styled.button`
  $(primary, secondary) => 
      switch(true) 
        case primary:
          return `background-color : green`
        case secondary:
          return `background-color : red`
      
    
  
`

【讨论】:

【参考方案5】:

样式化组件还接受一个函数,您可以在其中读取道具。此外,如果您选择传递主题道具,您还可以为您的主题定义一个对象。


const themes = 
  dark: css `
     background: $colors.dark;
     color: $colors.light;
  `,
  light: css`
     background: $colors.light;
     color: $colors.dark;
  `

export const Navbar = styled.nav((theme)=>`
  width: 100%;
  background: $colors.light;
  color: $colors.dark;
  ... // rest of the css

  $theme?themes[theme]:''

  `)

<Navbar theme="dark" />

【讨论】:

【参考方案6】:

使用Styled-tools的解决方案

根据您的具体情况

因为你只有两个主题,一个默认是light,一个是dark,你可以切换到一个,你只需要检查它是否是暗模式。

import ifProp from "styled-tools";

export const Navbar = styled.nav`
  $ifProp("dark",
    css`
      background: $colors.dark;
      color: $colors.light;
    `,
    css`
      background: $colors.light;
      color: $colors.dark;
    `,

  )
`;

并使用&lt;Navbar $dark=isDarkMode /&gt;进行渲染

更通用的解决方案

当然,您仍然希望使用深色/浅色等主题方法。设置变体会使事情变得更容易。例如,您可以在单独的枚举中跟踪您想要的不同主题。像这样:

enum Themes 
    DARK = "dark",
    LIGHT = "light",

您可以在稍后的样式中指定:

import switchProp from "styled-tools";

export const Navbar = styled.nav`
  $switchProp(
    dark: css`
      background: $colors.dark;
      color: $colors.light;
    `,
    light: css`
      background: $colors.light;
      color: $colors.dark;
    `,

  )
`;

然后渲染&lt;Navbar variant=Theme.LIGHT /&gt;&lt;Navbar variant=Theme.DARK /&gt;

参考文献

transient props switch prop

【讨论】:

【参考方案7】:

怎么样:

const StyledButton = styled.button`
    padding: 8px 16px;
    border-radius: $props => props.rounded ? '10px' : '0px';
    $props => 
        switch (props.type) 
            case 'primary':
                return `
                    background-color : #000;
                    color: #fff;
                    border: 1px solid #000000;
                `;
            case 'secondary':
                return `
                    background-color : #DEDEDE;
                    border: 1px solid #999;
                `;
        
    
`;

【讨论】:

以上是关于样式化组件的多个道具选项的主要内容,如果未能解决你的问题,请参考以下文章

使用状态自定义样式的反应+样式化组件

在样式化组件中设置 React 组件道具

样式化组件——从父级访问道具

TypeScript:为样式化的组件元素扩展 React 组件道具

在不工作之前使用样式化组件并将道具传递给伪元素

使用 Emotion.sh 从样式化组件传递道具