[英]Emotion CSS-in-JS - how to add conditional CSS based on component props?
I'd like to have a component, styled with Emotion , that takes props that ultimately control the styling.我想要一个带有Emotion样式的组件,它采用最终控制样式的道具。 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).例如,考虑一个
GridCol
组件,它有各种改变内边距和宽度的道具(宽度可以在不同的视口宽度之间改变)。
I'd like to use an API like this:我想使用这样的 API:
<GridCol gutter size="2>
// or alternatively, like this:
<GridCol gutter size={{
m: 2,
l: 4
}}>
There are three things happening here:这里发生了三件事:
gutter
is a boolean prop that adds some horizontal padding to the column gutter
是一个布尔道具,它向列添加一些水平填充size
prop can be a string or an object. size
道具可以是字符串或对象。 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. Emotion 的文档不清楚如何处理这种性质的样式,至少我没有见过,所以我希望能找到一个通用的解决方案。
For the gutter
prop, it is trivial:对于
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'};
`
For the size
prop, it becomes more complicated, I'd like the resultant CSS to look something like this:对于
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%;
}
`
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. width
值将由 prop 的 key 决定,它对应于breakpoints
对象中的一个值,这部分不是微不足道的,但我不知道如何动态生成所需的 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..
我的感觉是我应该创建一个无状态的功能组件,为每个条件生成 css,然后在最后加入 CSS..
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.在这个例子中,在每次渲染时都会创建一个新的样式组件,这对性能来说很糟糕。
Any expression, or interpolation, can be a function.任何表达式或插值都可以是函数。 This function will receive 2 arguments:
props
and context
此函数将接收 2 个参数:
props
和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'};
`
As for the size
prop in your example, I would use the following pattern.至于您示例中的
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%;
}
`
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.这是一个非常强大的模式,可用于在您的项目中组合可重用的动态样式。
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如果您对利用此模式的其他库感兴趣,请查看https://github.com/emotion-js/facepaint和https://github.com/jxnblk/styled-system
If you are looking for a way to implement conditional styles with Emotion's css
prop, you can do something like this:如果您正在寻找一种使用 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>
);
};
More details on this here: https://seanconnolly.dev/emotion-conditionals此处有更多详细信息: https : //seanconnolly.dev/emotion-conditionals
Emotion has a helper called cx that provides functionality similar to the popular classnames library. Emotion 有一个名为cx的帮助程序,它提供类似于流行的类名库的功能。 You can use this to write conditionals more easily:
您可以使用它来更轻松地编写条件:
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' },
)}
/>
);
(Adapted from the linked docs) (改编自链接的文档)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.