Styled Components 备忘清单
====
[](https://npmjs.org/package/styled-components)
[](https://www.npmjs.com/package/styled-components)
[](https://github.com/styled-components/styled-components/network/dependents)
[](https://github.com/styled-components/styled-components)
此快速参考备忘单提供了使用 CSS in JS 工具的各种方法
入门
----
### 安装
[Styled Components](https://styled-components.com) 是增强 CSS 在 React 组件系统样式的 CSS in JS 的最佳实践。
- [VSCode styled-components](https://github.com/styled-components/vscode-styled-components) _有代码高亮和代码提示_
- [VIM styled-components](https://github.com/styled-components/vim-styled-components) _有代码高亮_
- [WebStorm styled-components](https://github.com/styled-components/webstorm-styled-components) _有代码高亮和代码提示_
安装依赖和 TypeScript 类型依赖
```bash
npm install --save styled-components
```
### 快速开始
```jsx
import styled from 'styled-components';
```
创建一个 Title 组件
```jsx
// 该组件将呈现具有样式的
标签
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
`;
```
创建一个 Wrapper 组件
```jsx
// 该组件将呈现具有某些样式的 标记
const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`;
```
像使用其他 React 组件一样使用 Title/Wrapper - 除了它们的样式!
```jsx
function Demo() {
return (
Hello World!
);
}
```
### 根据 Props 适配
```jsx
import styled from 'styled-components';
const Button = styled.button`
/* 根据主要 props 调整颜色 */
background: ${
props =>
props.primary ? "blue" : "white"
};
color: ${
props =>
props.primary ? "white" : "blue"
};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid blue;
border-radius: 3px;
`;
```
使用 `primary` props 控制按钮样式
```jsx {5}
function Demo() {
return (
);
}
```
### 扩展样式
```jsx {7}
const Button = styled.button`
color: palevioletred;
border: 2px solid palevioletred;
border-radius: 3px;
`;
// 基于 Button 的新组件,但具有一些覆盖样式
const TomatoButton = styled(Button)`
color: tomato;
border-color: tomato;
`;
const Demo = () => (
番茄色按钮
);
```
### 扩展样式改变标签 (as)
```jsx {17,20}
const Button = styled.button`
color: palevioletred;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
display: block;
`;
const TomatoButton = styled(Button)`
color: tomato;
border-color: tomato;
`;
const Demo = () => (
番茄按钮样式的链接
);
```
### 自定义组件(as)
```jsx {20}
const Button = styled.button`
color: palevioletred;
font-size: 1em;
border: 2px solid palevioletred;
display: block;
`;
const ReversedButton = props => (
);
render(
);
```
### 样式化任何组件
```jsx
const Link = ({ className, children }) => (
{children}
);
const StyledLink = styled(Link)`
color: palevioletred;
font-weight: bold;
`;
```
### 在 render 之外定义 Styled 组件
```jsx {3}
const Box = styled.div`/* ... */`;
const Wrapper = ({ message }) => {
// ⚠️ 不能在这里定义 styled 组件
return (
{message}
);
};
```
注意:组件 `Box` 不能放到 `Wrapper` 函数组件里面
### 传入值
```jsx {3,4,17}
const Input = styled.input`
color: ${
props =>
props.inputColor || "palevioletred"
};
background: papayawhip;
`;
const Demo = () => (
);
```
### 样式对象
```jsx {2,5}
const PropsBox = styled.div(props => ({
background: props.background,
height: '50px',
width: '50px',
fontSize: '12px'
}));
```
在组件中使用
```jsx {5}
const Example = () => {
return (
);
}
```
注意:样式对象里面的样式并不是 CSS 中的写法。
### CSSModules => styled
```jsx
import React, { useState } from 'react';
import styles from './styles.css';
function ExampleCounter() {
const [count, setCount] = useState(0)
return (
{count}
);
}
```
#### 👇👇 与下面 **styled** 写法等效 👇👇
```jsx
import styled from 'styled-components';
const StyledCounter = styled.div`
/* ... */
`;
const Paragraph = styled.p`
/* ... */
`;
const Button = styled.button`
/* ... */
`;
function ExampleCounter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count +1);
}
const decrement = () => {
setCount(count -1);
}
return (
{count}
);
}
```
### 伪元素、伪选择器和嵌套
```jsx {3,6,9,12,15}
const Thing = styled.div.attrs((/* props */) => ({ tabIndex: 0 }))`
color: blue;
&:hover { /* 悬停时 */
color: red;
}
& ~ & { /* 作为 的兄弟,但可能不直接在它旁边 */
background: tomato;
}
& + & { /* 旁边的 */
background: lime;
}
&.something { /* 标记有一个额外的 CSS 类 “.something” */
background: orange;
}
.something-else & { /* 在另一个标记为 “.something-else” 的元素中 */
border: 1px solid;
}
`;
render(
Hello world!
你怎么样?
艳阳高照...
今天真是美好的一天。
你不觉得吗?
灿烂
);
```
### 改变 styled 组件样式
```jsx {13,21}
import { css } from 'styled-components'
import styled from 'styled-components'
const Input = styled.input.attrs({
type: "checkbox"
})``;
const LabelText = styled.span`
${(props) => {
switch (props.$mode) {
case "dark":
return css`
color: white;
${Input}:checked + && {
color: blue;
}
`;
default:
return css`
color: black;
${Input}:checked + && {
color: red;
}
`;
}
}}
`;
function Example() {
return (
);
}
```
### 全局样式 createGlobalStyle
```jsx {3,11}
import {
styled,
createGlobalStyle
} from 'styled-components'
const Thing = styled.div`
&& {
color: blue;
}
`;
const GlobalStyle = createGlobalStyle`
div${Thing} {
color: red;
}
`;
const Example = () => (
我是蓝色的
);
```
### className 使用
```JSX
const Thing = styled.div`
color: blue;
/* 中标记为“.something”的元素 */
.something {
border: 1px solid;
}
`;
function Example() {
return (
)
}
```
### 共享样式片段
```jsx
const rotate = keyframes`
from {top:0px;}
to {top:200px;}
`;
// ❌ 这将引发错误!
const styles = `
animation: ${rotate} 2s linear infinite;
`;
// ✅ 这将按预期工作
const styles = css`
animation: ${rotate} 2s linear infinite;
`;
```
### Class 组件样式定义
```jsx {5}
class NewHeader extends React.Component {
render() {
return (
);
}
}
const StyledA = styled(NewHeader)``
const Box = styled.div`
${StyledA} {
/* 变更 NewHeader 样式 */
}
`;
```
### 附加额外的 Props
```jsx {3,5,13,14,23}
const Input = styled.input.attrs(props=>({
// 我们可以定义静态道具
type: "text",
// 或者我们可以定义动态的
size: props.size || "1em",
}))`
color: palevioletred;
font-size: 1em;
border: 2px solid palevioletred;
border-radius: 3px;
/* 这里我们使用动态计算的 props */
margin: ${props => props.size};
padding: ${props => props.size};
`;
```
使用 `Input` 组件
```jsx
function Example() {
return (
)
}
```
### 覆盖 .attrs
```jsx {11}
const Input = styled.input.attrs(props=>({
type: "text",
size: props.size || "1em",
}))`
border: 2px solid palevioletred;
margin: ${props => props.size};
padding: ${props => props.size};
`;
// Input 的attrs会先被应用,然后这个 attrs obj
const PasswordInput = styled(Input).attrs({
type: "password",
})`
/* 同样,border 将覆盖 Input 的边框 */
border: 2px solid aqua;
`;
```
使用 `Input` 和 `PasswordInput` 组件
```jsx {5,11}
render(
);
```
### 动画
创建关键帧
```jsx
const rotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
```
我们创建一个 `Rotate` 组件
```jsx
// 它将在两秒内旋转我们传递的所有内容
const Rotate = styled.div`
display: inline-block;
animation: ${rotate} 2s linear infinite;
padding: 2rem 1rem;
font-size: 1.2rem;
`;
```
使用 `Rotate` 组件
```jsx
function Example() {
return (
< 💅🏾 >
)
}
```
### isStyledComponent
```jsx
import React from 'react'
import styled, { isStyledComponent } from 'styled-components'
import MaybeStyledComponent from './my'
let TargetedComponent = isStyledComponent(MaybeStyledComponent)
? MaybeStyledComponent
: styled(MaybeStyledComponent)``;
const ParentComponent = styled.div`
color: cornflowerblue;
${TargetedComponent} {
color: tomato;
}
`;
```
### ThemeConsumer
```jsx
import {
ThemeConsumer
} from 'styled-components'
function Example() {
return (
{theme => (
主题色是 {theme.color}
)}
);
}
```
TypeScript
----
### 安装
Web 应用上安装 styled
```bash
npm install -D @types/styled-components
```
React Native 应用上安装 styled
```bash
npm install -D \
@types/styled-components \
@types/styled-components-react-native
```
如果对 TypeScript 不熟悉,参考 [TypeScript 备忘清单](./typescript.md)
### 自定义 Props
```tsx
import styled from 'styled-components';
interface TitleProps {
readonly isActive: boolean;
}
const Title = styled.h1`
color: ${(props) => (
props.isActive
? props.theme.colors.main
: props.theme.colors.secondary
)};
`;
```
### 简单的 Props 类型定义
```tsx
import styled from 'styled-components';
import Header from './Header';
const Header = styled.header`
font-size: 12px;
`;
const NewHeader = styled(Header)<{
customColor: string;
}>`
color: ${(props) => props.customColor};
`;
```
### 禁止转移到子组件($)
```tsx {5}
import styled from 'styled-components';
import Header from './Header';
interface ReHeader {
$customColor: string;
}
const ReHeader = styled(Header)`
color: ${
props => props.$customColor
};
`;
```
禁止 `customColor` 属性转移到 `Header` 组件,在其前面加上美元(`$`)符号
### 函数组件类型继承
```tsx {8,13}
import { FC, PropsWithRef, DetailedHTMLProps, ImgHTMLAttributes } from 'react';
import styled from 'styled-components';
const Img = styled.img`
height: 32px;
width: 32px;
`;
export interface ImageProps extends DetailedHTMLProps<
ImgHTMLAttributes, HTMLImageElement
> {
text?: string;
};
export const Image: FC> = (props) => (
);
```
React Native
----
### 基础实例
```jsx
import React from 'react'
import styled from 'styled-components/native'
const StyledView = styled.View`
background-color: papayawhip;
`;
const StyledText = styled.Text`
color: palevioletred;
`;
class MyReactNativeComponent extends React.Component {
render() {
return (
Hello World!
);
}
}
```
### React Native 中写 CSS
```jsx
import styled from 'styled-components/native'
const RotatedBox = styled.View`
transform: rotate(90deg);
text-shadow-offset: 10px 5px;
font-variant: small-caps;
margin: 5px 7px 2px;
`;
function Example() {
return (
)
}
```
与 web 版本的一些区别是,您不能使用关键帧(`keyframes`)和 `createGlobalStyle` 助手,因为 React Native 不支持关键帧或全局样式。如果您使用媒体查询或嵌套 CSS,我们也会警告您。
高级用法
----
### 主题化
```jsx
import styled, { ThemeProvider } from 'styled-components'
// 定义我们的按钮,但这次使用 props.theme
const Button = styled.button`
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border-radius: 3px;
/* 使用 theme.main 为边框和文本着色 */
color: ${props => props.theme.main};
border: 2px solid ${props => props.theme.main};
`;
// 我们正在为未包装在 ThemeProvider 中的按钮传递默认主题
Button.defaultProps = {
theme: {
main: "palevioletred"
}
}
// 定义 props.theme 的外观
const theme = {
main: "mediumseagreen"
};
render(
);
```
### 功能主题
```jsx
import styled, { ThemeProvider } from 'styled-components'
// 定义我们的按钮,但这次使用 props.theme
const Button = styled.button`
color: ${props => props.theme.fg};
border: 2px solid ${props => props.theme.fg};
background: ${props => props.theme.bg};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border-radius: 3px;
`;
// 在主题上定义我们的`fg`和`bg`
const theme = {
fg: "palevioletred",
bg: "white"
};
// 这个主题交换了`fg`和`bg`
const invertTheme = ({ fg, bg }) => ({
fg: bg,
bg: fg
});
render(
);
```
### 通过 withTheme 高阶组件
```jsx
import { withTheme } from 'styled-components'
class MyComponent extends React.Component {
render() {
console.log('Current theme: ', this.props.theme)
// ...
}
}
export default withTheme(MyComponent)
```
### useContext 钩子
```jsx
import { useContext } from 'react'
import { ThemeContext } from 'styled-components'
const MyComponent = () => {
const themeContext = useContext(ThemeContext)
console.log('Current theme: ', themeContext)
// ...
}
```
### useTheme 自定义钩子
```jsx
import {useTheme} from 'styled-components'
const MyComponent = () => {
const theme = useTheme()
console.log('Current theme: ', theme)
// ...
}
```
### 主题 props
```jsx
import {
ThemeProvider,
styled
} from 'styled-components';
// 定义我们的按钮
const Button = styled.button`
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
/* 使用 theme.main 为边框和文本着色 */
color: ${props => props.theme.main};
border: 2px solid ${props => props.theme.main};
`;
// 定义主题的外观
const theme = {
main: "mediumseagreen"
};
```
使用自定义主题组件
```jsx
render(
);
```
### Refs
```jsx
import {
ThemeProvider,
styled
} from 'styled-components';
const Input = styled.input`
border: none;
border-radius: 3px;
`;
class Form extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
render() {
return (
{
this.inputRef.current.focus()
}}
/>
);
}
}
```
使用 `Form` 组件
```jsx
function Example() {
return (
)
}
```
### 特异性问题
在文件 `MyComponent.js` 中定义 `MyComponent` 组件。
```jsx
const MyComponent = styled.div`
background-color: green;
`;
```
定义样式 `my-component.css`
```css
.red-bg {
background-color: red;
}
```
使用 `MyComponent` 组件
```jsx
```
由于某种原因,这个组件仍然有绿色背景,即使你试图用 `red-bg` 类覆盖它!
#### 解决方案
```css
.red-bg.red-bg {
background-color: red;
}
```
### ThemeProvider
```jsx
import styled, { ThemeProvider } from 'styled-components'
const Box = styled.div`
color: ${props => props.theme.color};
`;
const Example = () => (
I'm mediumseagreen!
);
```
### shouldForwardProp
```jsx
const Comp = styled('div').withConfig({
shouldForwardProp: (prop, defaultValidatorFn) =>
!['hidden'].includes(prop) && defaultValidatorFn(prop),
}).attrs({ className: 'foo' })`
color: red;
&.foo {
text-decoration: underline;
}
`;
const Example = () => (
Drag Me!
);
```