安装 yarn add styled-components
引入 import styled from 'styled-components'
先来个最基础的例子
// 创建一个 Title 组件,它将渲染一个附加了样式的 <h1> 标签
const Title = styled.h1`font-size: 1.5em;text-align: center;color: palevioletred;
`;// 创建一个 Wrapper 组件,它将渲染一个附加了样式的 <section> 标签
const Wrapper = styled.section`padding: 4em;background: papayawhip;
`;// 就像使用常规 React 组件一样使用 Title 和 Wrapper
render(<Wrapper><Title>Hello World!</Title></Wrapper>
);
先解析第一行 styled
是引入的styled,.
后面的是你要创建的标签名,` `
中间包裹的就是正常的CSS样式(可以写变量,传props值,后面会讲到),然后你这些复制给一个大写开头的Title变量,那么Title在styled的作用下就变成了一个组件,直接把组件渲染出来就可以了
基于属性的适配
const Button = styled.button`/* Adapt the colors based on primary prop */background: ${props => props.primary ? "palevioletred" : "white"};color: ${props => props.primary ? "white" : "palevioletred"};font-size: 1em;margin: 1em;padding: 0.25em 1em;border: 2px solid palevioletred;border-radius: 3px;
`;render(<div><Button>Normal</Button><Button primary>Primary</Button></div>
);
样式继承
const Button = styled.button`color: palevioletred;font-size: 1em;margin: 1em;padding: 0.25em 1em;border: 2px solid palevioletred;border-radius: 3px;
`;// 一个继承 Button 的新组件, 重载了一部分样式
const TomatoButton = styled(Button)`color: tomato;border-color: tomato;
`;render(<div><Button>Normal Button</Button><TomatoButton>Tomato Button</TomatoButton></div>
);
多态 "as" polymorphic prop
const Button = styled.button`display: inline-block;color: palevioletred;font-size: 1em;margin: 1em;padding: 0.25em 1em;border: 2px solid palevioletred;border-radius: 3px;
`;const TomatoButton = styled(Button)`color: tomato;border-color: tomato;
`;render(<div><Button>Normal Button</Button><Button as="a" href="/">Link with Button styles</Button><TomatoButton as="a" href="/">Link with Tomato Button styles</TomatoButton></div>
);
这也完美适用于自定义组件:
const Button = styled.button`display: inline-block;color: palevioletred;font-size: 1em;margin: 1em;padding: 0.25em 1em;border: 2px solid palevioletred;border-radius: 3px;
`;const ReversedButton = props => <button {...props} children={props.children.split('').reverse()} />render(<div><Button>Normal Button</Button><Button as={ReversedButton}>Custom Button with Normal Button styles</Button></div>
);
给任何组件添加样式
styled方法适用于任何最终向 DOM 元素传递 className 属性的组件,当然也包括第三方组件.注意在 react-native 中,请使用 style 而不是 className.// 下面是给 react-router-dom Link 组件添加样式的示例
const Link = ({ className, children }) => (<a className={className}>{children}</a>
);const StyledLink = styled(Link)`color: palevioletred;font-weight: bold;
`;render(<div><Link>Unstyled, boring Link</Link><br /><StyledLink>Styled, exciting Link</StyledLink></div>
);
也可以传递标签给styled(), 比如: styled("div"). 实际上styled.tagname的方式就是 styled(tagname)`的别名.
属性传递
const Input = styled.input`padding: 0.5em;margin: 0.5em;color: ${props => props.inputColor || "palevioletred"};background: papayawhip;border: none;border-radius: 3px;
`;// 渲染两个样式化的 text input,一个标准颜色,一个自定义颜色
render(<div><Input defaultValue="@probablyup" type="text" /><Input defaultValue="@geelen" type="text" inputColor="rebeccapurple" /></div>
);
注意, inputColor prop并没有传递给 DOM, 但是type和defaultValue 都传递了. styled-components足够智能,会自动过滤掉所有非标准 attribute.
styled-components 如何在组件中工作?
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>)}
}
伪元素,伪类选择器和嵌套
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"}
`
如果只写选择器而不带&,则指向组件的子节点.
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>
)
附加额外的属性 (v2)
为了避免仅为传递一些props来渲染组件或元素而使用不必要的wrapper, 可以使用 .attrs
constructor. 通过它可以添加额外的 props 或 attributes 到组件.
举例来说,可以通过这种方式给元素添加静态 props,或者传递第三方 prop 给组件(比如传递activeClassName
给 React Router 的 Link
). 此外也可以将dynamic props 添加到组件. .attrs
对象也接收函数,返回值也将合并进 props.
示例如下:
source-js-jsx
const Input = styled.input.attrs({// static propstype: "password",// dynamic propsmargin: props => props.size || "1em",padding: props => props.size || "1em"
})`color: palevioletred;font-size: 1em;border: 2px solid palevioletred;border-radius: 3px;/* dynamically computed props */margin: ${props => props.margin};padding: ${props => props.padding};
`;render(<div><Input placeholder="A small text input" size="1em" /><br /><Input placeholder="A bigger text input" size="2em" /></div>
);
动画
虽然使用@keyframes的 CSS 动画不限于单个组件,但我们仍希望它们不是全局的(以避免冲突). 这就是为什么 styled-components 导出 keyframes helper 的原因: 它将生成一个可以在 APP 应用的唯一实例:
// Create the keyframes
const rotate = keyframes`from {transform: rotate(0deg);}to {transform: rotate(360deg);}
`;// Here we create a component that will rotate everything we pass in over two seconds
const Rotate = styled.div`display: inline-block;animation: ${rotate} 2s linear infinite;padding: 2rem 1rem;font-size: 1.2rem;
`;