styled-components Coming from CSS
styled-components 如何在组件中工作?
如果你熟悉在组件中导入 CSS(例如 CSSModules),那么下面的写法你一定不陌生:
import React from 'react' import styles from './styles.css' export default class Counter extends React.Component { state = { count: 0 } increment = () => this.setState({ count: this.state.count + 1 }) decrement = () => this.setState({ count: this.state.count - 1 }) render() { return ( <div className={styles.counter}> <p className={styles.paragraph}>{this.state.count}</p> <button className={styles.button} onClick={this.increment}> + </button> <button className={styles.button} onClick={this.decrement}> - </button> </div> ) } }
由于 Styled Component 是 HTML 元素和作用在元素上的样式规则的组合, 我们可以这样编写Counter:
import React from 'react' import styled from 'styled-components' const StyledCounter = styled.div` /* ... */ ` const Paragraph = styled.p` /* ... */ ` const Button = styled.button` /* ... */ ` export default class Counter extends React.Component { state = { count: 0 } increment = () => this.setState({ count: this.state.count + 1 }) decrement = () => this.setState({ count: this.state.count - 1 }) render() { return ( <StyledCounter> <Paragraph>{this.state.count}</Paragraph> <Button onClick={this.increment}>+</Button> <Button onClick={this.decrement}>-</Button> </StyledCounter> ) } }
注意,我们在StyledCounter添加了"Styled"前缀,这样组件Counter 和StyledCounter 不会明明冲突,而且可以在 React Developer Tools 和 Web Inspector 中轻松识别.
在 render 方法之外定义 Styled Components
在 render 方法之外定义 styled component 很重要, 不然 styled component 会在每个渲染过程中重新创建. 这将阻止缓存生效并且大大降低了渲染速度,所以尽量避免这种情况.
推荐通过以下方式创建 styled components :
const StyledWrapper = styled.div` /* ... */ ` const Wrapper = ({ message }) => { return <StyledWrapper>{message}</StyledWrapper> }
而不是:
const Wrapper = ({ message }) => { // WARNING: 别这么干,会很慢!!! const StyledWrapper = styled.div` /* ... */ ` return <StyledWrapper>{message}</StyledWrapper> }
推荐阅读:Talia Marcassa 写了一篇很精彩的有关styled-components实际应用的文章,包含许多实用的见解以及与其它方案的比较Styled Components: To Use or Not to Use?
伪元素,伪类选择器和嵌套
styled-component 所使用的预处理器stylis支持自动嵌套的 scss-like 语法,示例如下:
const Thing = styled.div` color: blue; `
伪元素和伪类无需进一步细化,而是自动附加到了组件:
const Thing = styled.button` color: blue; ::before { content: '????'; } :hover { color: red; } ` render( <Thing>Hello world!</Thing> )
对于更复杂的选择器,可以使用与号(&)来指向主组件.以下是一些示例:
const Thing = styled.div.attrs({ tabIndex: 0 })` color: blue; &:hover { color: red; // <Thing> when hovered } & ~ & { background: tomato; // <Thing> as a sibling of <Thing>, but maybe not directly next to it } & + & { background: lime; // <Thing> next to <Thing> } &.something { background: orange; // <Thing> tagged with an additional CSS class ".something" } .something-else & { border: 1px solid; // <Thing> inside another element labeled ".something-else" } ` render( <React.Fragment> <Thing>Hello world!</Thing> <Thing>How ya doing?</Thing> <Thing className="something">The sun is shining...</Thing> <div>Pretty nice day today.</div> <Thing>Don't you think?</Thing> <div className="something-else"> <Thing>Splendid.</Thing> </div> </React.Fragment> )
如果只写选择器而不带&,则指向组件的子节点.
const Thing = styled.div` color: blue; .something { border: 1px solid; // an element labeled ".something" inside <Thing> display: block; } ` render( <Thing> <label htmlFor="foo-button" className="something">Mystery button</label> <button id="foo-button">What do I do?</button> </Thing> )
最后,&可以用于增加组件的差异性;在处理混用 styled-components 和纯 CSS 导致的样式冲突时这将会非常有用:
const Thing = styled.div` && { color: blue; } ` const GlobalStyle = createGlobalStyle` div${Thing} { color: red; } ` render( <React.Fragment> <GlobalStyle /> <Thing> I'm blue, da ba dee da ba daa </Thing> </React.Fragment> )