为样式组件创建响应式道具

Mos*_*she 1 javascript reactjs styled-components react-props react-component

我正在尝试为样式组件创建响应式道具,如下所示。首先,我们有一个组件(假设是一个按钮):

<Button primary large>Click Me</Button>
Run Code Online (Sandbox Code Playgroud)

该按钮将获得主要背景颜色和大尺寸(由主题文件确定)。

我现在想创建此按钮的响应版本。这就是我希望的工作方式:

<Button 
  primary 
  large 
  mobile={{size: 'small', style: 'secondary'}}
  tablet={size: 'small'}} 
  widescreen={{style: 'accent'}}
>
  Click Me
</Button>
Run Code Online (Sandbox Code Playgroud)

我现在有相同的按钮,但样式和尺寸因不同的屏幕尺寸而异。

现在,我已经让它工作了——但它涉及到很多重复的代码。这是它的外观示例:

const Button = styled('button')(
  ({
    mobile,
    tablet,
    tabletOnly,
    desktop,
    widescreen
  }) => css`

      ${mobile &&
      css`
        @media screen and (max-width: ${theme.breakpoints.mobile.max}) {
          background-color: ${colors[mobile.style] || mobile.style};
          border: ${colors[mobile.style] || mobile.style};
          border-radius: ${radii[mobile.radius] || mobile.radius};
          color: ${mobile.style && rc(colors[mobile.style] || mobile.style)};

        }
      `}

    ${tablet &&
      css`
        @media screen and (min-width: ${theme.breakpoints.tablet.min}), print {
          background-color: ${colors[tablet.style] || tablet.style};
          border: ${colors[tablet.style] || tablet.style};
          border-radius: ${radii[tablet.radius] || tablet.radius};
          color: ${tablet.style && rc(colors[tablet.style] || tablet.style)};
        }
      `}

    ${tabletOnly &&
      css`
        @media screen and (min-width: ${theme.breakpoints.mobile.min}) and (max-width: ${theme.breakpoints.tablet.max}) {
          background-color: ${colors[tabletOnly.style] || tabletOnly.style};
          border: ${colors[tabletOnly.style] || tabletOnly.style};
          border-radius: ${radii[tabletOnly.radius] || tabletOnly.radius};
          color: ${tabletOnly.style &&
            rc(colors[tabletOnly.style] || tabletOnly.style)};
        }
      `}
`
Run Code Online (Sandbox Code Playgroud)

我正在寻找一种简化此代码的方法。基本上,我只想编写一次 CSS 样式,然后根据查询对象生成不同的道具和媒体查询,如下所示:

const mediaQueries = {
  mobile: {
    min: '0px',
    max: '768px'
  },
  tablet: {
    print: true,
    min: '769px',
    max: '1023px'
  },
  desktop: {
    min: '1024px',
    max: '1215px'
  },
  widescreen: {
    min: '1216px',
    max: '1407px'
  },
  fullhd: {
    min: '1408px',
    max: null
  }
}
Run Code Online (Sandbox Code Playgroud)

我想我应该能够创建一个循环遍历对象mediaQueries并为每次迭代插入适当的 css 的函数。但是,我似乎不知道如何做到这一点。

关于如何做到这一点有什么想法吗?

另外,提前感谢您提供的任何帮助。

Wil*_*des 5

也许您正在寻找这样的东西:

\n\n
import { css } from "styled-components";\n\n//mobile first approach min-width\nconst\xc2\xa0screenSizes\xc2\xa0=\xc2\xa0{\n\xc2\xa0\xc2\xa0fullhd: 1408,\n  widescreen:\xc2\xa01215,\n\xc2\xa0\xc2\xa0desktop:\xc2\xa01023,\n\xc2\xa0\xc2\xa0tablet:\xc2\xa0768,\n\xc2\xa0\xc2\xa0mobile:\xc2\xa00\n}\nconst\xc2\xa0media\xc2\xa0=\xc2\xa0Object\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0.keys(screenSizes)\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0.reduce((acc,\xc2\xa0label)\xc2\xa0=>\xc2\xa0{\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0acc[label]\xc2\xa0=\xc2\xa0(...args)\xc2\xa0=>\xc2\xa0css`\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0@media\xc2\xa0(min-width:\xc2\xa0${screenSizes[label]\xc2\xa0/\xc2\xa016}rem)\xc2\xa0{\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0${css(...args)}\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0}\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0`\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0return\xc2\xa0acc\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0},\xc2\xa0{});\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后你只需像这样导入和使用:

\n\n
import media from \'./media\'\nconst button = styled.button`\n   ${({large , small})=> media.mobile`\n      color: red;\n      font-size: ${large ? \'2em\' : \'1em\'};\n   `}\n`\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里有一些进一步的阅读,包括使用主题:

\n\n

样式组件中的媒体查询

\n\n

使用道具:

\n\n

使用与上面相同的媒体查询对象:

\n\n

创建一个辅助函数将样式对象格式化为 css 字符串:

\n\n
const formatCss = (styleObject) => {\n    return JSON.stringify(styleObject)\n        .replace(/[{}"\']/g,\'\')\n        .replace(/,/g,\';\') \n        + \';\'\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

创建另一个辅助函数来映射样式并通过映射其键并使用括号表示法动态添加查询来生成查询:

\n\n
const mapQueries = (myQueries) =>{\n    return Object.keys(myQueries).map(key=> media[key]`\n        ${formatCss(myQueries[key])}\n    `)\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在您的样式组件中:

\n\n
export const Button = styled.button`\n    ${({myQueries}) => !myQueries ? \'\' : mapQueries(myQueries)}\n`\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后将 myQueries 属性添加到您的组件中,如下所示(注意使用css-formatted键而不是javascriptFormatted最后将 myQueries 属性添加到您的组件中,如下所示(请注意为简单起见

\n\n
<Button myQueries={{\n    mobile:{ color:\'red\' },\n    tablet:{ color:\'blue\', "background-color":\'green\'},\n    desktop:{ height:\'10rem\' , width:\'100%\'}\n}}>Button</Button>\n
Run Code Online (Sandbox Code Playgroud)\n