Emotion CSS-in-JS-如何基于组件属性添加条件CSS? [英] Emotion CSS-in-JS - how to add conditional CSS based on component props?

查看:327
本文介绍了Emotion CSS-in-JS-如何基于组件属性添加条件CSS?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望有一个使用 Emotion 样式的组件,该组件最终需要道具控制样式.例如,考虑一个GridCol组件,它具有各种可更改填充和宽度的属性(可以在不同的视口宽度之间更改宽度).

I'd like to have a component, styled with Emotion, that takes props that ultimately control the styling. For example, consider a GridCol component that has various props that change the padding and width (the width can be changed across different viewport widths).

我想使用这样的API:

I'd like to use an API like this:

<GridCol gutter size="2>

// or alternatively, like this:

<GridCol gutter size={{
  m: 2,
  l: 4
}}>

这里发生了三件事:

  • gutter是一个布尔型道具,为列添加了一些水平填充
  • size道具可以是字符串或对象.如果它是一个字符串,我们只需添加几行CSS就可以了,但是,如果它是一个对象,则需要基于在别处设置的断点对象插入一些媒体查询.
  • the gutter is a boolean prop that adds some horizontal padding to the column
  • the size prop can be a string or an object. If it is a string, we just add a few lines of CSS and we're good, however, if it is an object, we need to insert some media-queries based on a breakpoints object that is set elsewhere.

情感文档尚不清楚如何处理这种性质的样式,至少我没有看到它,所以我希望可以找到一个通用的解决方案.

Emotion's docs are not clear how to handle styling of this nature, at least I have not seen it, so I was hoping that a common solution could be found.

对于gutter道具,这是微不足道的:

For the gutter prop, it is trivial:

const GridCol = props => styled('div')`
  display: block;
  box-sizing: border-box;
  flex: 1 0 0;
  min-width: 0;
  padding: ${props.gutter ? `0 10px` : '0'};
`

对于size道具,它变得更加复杂,我希望生成的CSS看起来像这样:

For the size prop, it becomes more complicated, I'd like the resultant CSS to look something like this:

const GridCol = props => styled('div')`
  display: block;
  box-sizing: border-box;
  flex: 1 0 0;
  min-width: 0;
  padding: ${props.gutter ? `0 10px` : '0'};

  /* styles here if  `size` is a string */
  width: 10%;

  /* styles here if  `size` is an object */
  @media screen and (min-width: 500px) {
      width: 20%;
  }


  @media screen and (min-width: 800px) {
      width: 30%;
  }


  @media screen and (min-width: 1100px) {
      width: 40%;
  }
`

width的值将由prop的键确定,该键对应于breakpoints对象中的值,这部分并不琐碎,但我不知道如何动态生成所需的CSS.

The width values will be determined by the prop's key, which corresponds to a value in a breakpoints object, this part is not trivial, but I don't know how to dynamically generate the css needed.

我敢肯定,我可以添加更多信息,尽管我已经进行了一些尝试,但目前都没有任何尝试.我的感觉是,我应该创建一个无状态功能组件,为每个条件生成css,然后在最后加入CSS.

I'm sure there's more info that I could add, I have made some attempts but none of them are working at the moment. My feeling is that I should create a stateless functional component that generates the css for each condition, then joins the CSS at the end..

推荐答案

这是一个很好的问题.首先,避免这种模式.

This is a great question. First, avoid this pattern.

const GridCol = props => styled('div')`
  display: block;
  box-sizing: border-box;
  flex: 1 0 0;
  min-width: 0;
  padding: ${props.gutter ? `0 10px` : '0'};
`

在此示例中,在每个渲染上都会创建一个新样式的组件,这对于性能来说是很糟糕的.

In this example, a new styled component is created on every render which is terrible for performance.

任何表达式或插值都可以是一个函数.此函数将接收2个参数:propscontext

Any expression, or interpolation, can be a function. This function will receive 2 arguments: props and context

const GridCol = styled('div')`
  display: block;
  box-sizing: border-box;
  flex: 1 0 0;
  min-width: 0;
  padding: ${props => props.gutter ? `0 10px` : '0'};
`

在您的示例中,对于size道具,我将使用以下模式.

As for the size prop in your example, I would use the following pattern.

import { css } from 'emotion'

const sizePartial = (props) => typeof props.size === 'string' ?
  css`width: 10%;` :
  css`
   @media screen and (min-width: 500px) {
      width: 20%;
   }


   @media screen and (min-width: 800px) {
      width: 30%;
   }


   @media screen and (min-width: 1100px) {
      width: 40%;
   }
 `

然后可以像在表达式中出现的任何其他函数一样使用局部函数.

You can then use the partial just like any other function that occurs in an expression.

const GridCol = styled('div')`
  display: block;
  box-sizing: border-box;
  flex: 1 0 0;
  min-width: 0;
  padding: ${props => props.gutter ? `0 10px` : '0'};
  ${sizePartial};
`

这是一种非常强大的模式,可用于在您的项目中组成可重用的动态样式.

This is an extremely powerful pattern that can be used to compose reusable dynamic styles across your project.

如果您对其他利用此模式的库感兴趣,请查看 https://github.com/emotion-js/facepaint

If you are interested in other libraries that leverage this pattern check out https://github.com/emotion-js/facepaint and https://github.com/jxnblk/styled-system

这篇关于Emotion CSS-in-JS-如何基于组件属性添加条件CSS?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆