11

我想要一个用Emotion设置样式的组件,它采用最终控制样式的道具。例如,考虑一个GridCol具有各种改变填充和宽度的道具的组件(宽度可以在不同的视口宽度上改变)。

我想使用这样的 API:

<GridCol gutter size="2>

// or alternatively, like this:

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

这里发生了三件事:

  • thegutter是一个布尔属性,它为列添加一些水平填充
  • sizeprop 可以是字符串或对象。如果它是一个字符串,我们只需添加几行 CSS 就可以了,但是,如果它是一个对象,我们需要根据在别处设置的断点对象插入一些媒体查询。

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

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

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 看起来像这样:

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 的 key 确定,它对应于breakpointsobject 中的一个 value,这部分并不简单,但我不知道如何动态生成所需的 css。

我确信我可以添加更多信息,我已经做了一些尝试,但目前没有一个有效。我的感觉是我应该创建一个无状态功能组件,为每个条件生成 css,然后在最后加入 css..

4

3 回答 3

26

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

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

在这个例子中,每次渲染都会创建一个新样式的组件,这对性能来说很糟糕。

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

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您示例中的道具,我将使用以下模式。

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%;
   }
 `

然后,您可以像使用表达式中出现的任何其他函数一样使用分部。

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};
`

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

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

于 2017-11-27T17:45:51.397 回答
7

如果您正在寻找一种使用 Emotion 的css道具实现条件样式的方法,您可以执行以下操作:

import { css } from '@emotion/core';

const styles = ({ isSelected }) => css`
  border: solid 1px black;
  border-radius: 10px;
  padding: 16px;
  cursor: pointer;
  ${isSelected === true &&
  `
    background-color: #413F42;
    color: white;
  `}
`;

const ConditionalComponent = () => {
  const [isSelected, setIsSelected] = useState(false);
  return (
    <div css={styles({ isSelected })} onClick={() => setIsSelected(!isSelected)}>
      Click here to change styles.
    </div>
  );
};

更多细节在这里:https ://seanconnolly.dev/emotion-conditionals

于 2020-06-22T16:17:33.493 回答
2

Emotion 有一个名为cx的助手,它提供类似于流行的类名库的功能。您可以使用它更轻松地编写条件:

import { cx, css } from '@emotion/css'

const cls1 = css`
  font-size: 20px;
  background: green;
`

const foo = true
const bar = false

const SomeComponentWithProp = ({ foo }) => (
  <div
    className={cx(
      { [cls1]: foo === 'bar' },
    )}
  />
);

(改编自链接的文档)

于 2020-12-30T20:24:49.357 回答