diff --git a/README.md b/README.md
index 3b22cd7..8a8009e 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@ Quick Reference
[JavaScript](./docs/javascript.md)
[JSON](./docs/json.md)
[React](./docs/react.md)
+[Styled Components](./docs/styled-components.md)
[TOML](./docs/toml.md)
[Markdown](./docs/markdown.md)
[TypeScript](./docs/typescript.md)
diff --git a/docs/docker.md b/docs/docker.md
index 5869520..78998ae 100644
--- a/docs/docker.md
+++ b/docs/docker.md
@@ -25,12 +25,13 @@ $ docker run -d -p 80:80 docker/getting-started
在前台创建并运行容器
```shell
-$ docker run -it -p 8001:8080 --name my-nginx nginx
+$ docker run -it -p --rm 8001:8080 --name my-nginx nginx
```
----
- `-it` - 交互式 bash 模式
+- `--rm` - 容器终止运行后自动删除容器文件
- `-p 8001:8080` - 将 `8001` 端口映射到容器中的 `8080` 端口
- `--name my-nginx` - 指定名称
- `nginx` - 要使用的镜像
diff --git a/docs/jest.md b/docs/jest.md
index 47fb735..2835a17 100644
--- a/docs/jest.md
+++ b/docs/jest.md
@@ -63,8 +63,6 @@ describe('My work', () => {
})
```
-
-
### 测试结构
@@ -135,6 +133,97 @@ expect(value).toThrow(error)
.toThrowErrorMatchingSnapshot()
```
+### 快照
+
+
+```js
+expect(value)
+ .toMatchSnapshot()
+ .toMatchInlineSnapshot()
+```
+
+### Errors
+
+
+```js
+expect(value)
+ .toThrow(error)
+ .toThrowErrorMatchingSnapshot()
+```
+
+### Objects
+
+
+```js
+expect(value)
+ .toBeInstanceOf(Class)
+ .toMatchObject(object)
+ .toHaveProperty(keyPath, value)
+```
+
+### Objects
+
+
+```js
+expect(value)
+ .toContain(item)
+ .toContainEqual(item)
+ .toHaveLength(number)
+```
+
+### Numbers
+
+
+```js
+expect(value)
+ .toBeCloseTo(number, numDigits)
+ .toBeGreaterThan(number)
+ .toBeGreaterThanOrEqual(number)
+ .toBeLessThan(number)
+ .toBeLessThanOrEqual(number)
+```
+
+### Booleans
+
+
+```js
+expect(value)
+ .toBeFalsy()
+ .toBeNull()
+ .toBeTruthy()
+ .toBeUndefined()
+ .toBeDefined()
+```
+
+### Strings
+
+
+```js
+expect(value)
+ .toMatch(regexpOrString)
+```
+
+### NaN
+
+
+```js
+test('当值为 NaN 时通过', () => {
+ expect(NaN).toBeNaN();
+ expect(1).not.toBeNaN();
+});
+```
+
+### Others
+
+
+```js
+expect.extend(matchers)
+expect.any(constructor)
+expect.addSnapshotSerializer(serializer)
+
+expect.assertions(1)
+```
+
匹配器
----
@@ -388,8 +477,6 @@ expect(fn).toThrowErrorMatchingSnapshot()
### 实例
-请参阅 Jest 文档中的 [更多示例](https://jestjs.io/docs/en/tutorial-async)。
-
在异步测试中指定一些预期的断言是一个很好的做法,所以如果你的断言根本没有被调用,测试将会失败。
```js
@@ -409,6 +496,7 @@ beforeEach(expect.hasAssertions)
```
这将验证每个测试用例至少存在一个断言。 它还可以与更具体的 `expect.assertions(3)` 声明配合使用。
+请参阅 Jest 文档中的 [更多示例](https://jestjs.io/docs/en/tutorial-async)
### async/await
@@ -432,8 +520,8 @@ test('async test', (done) => {
setTimeout(() => {
try {
- const result = getAsyncOperationResult()
- expect(result).toBe(true)
+ const res = getAsyncOperatResult()
+ expect(res).toBe(true)
done()
} catch (err) {
done.fail(err)
@@ -469,18 +557,28 @@ test('call the callback', () => {
const callback = jest.fn()
fn(callback)
expect(callback).toBeCalled()
- expect(callback.mock.calls[0][1].baz).toBe('pizza') // 第一次调用的第二个参数
+ expect(callback.mock.calls[0][1].baz)
+ .toBe('pizza') // 第一次调用的第二个参数
+
// 匹配第一个和最后一个参数,但忽略第二个参数
- expect(callback).toHaveBeenLastCalledWith('meal', expect.anything(), 'margarita')
+ expect(callback)
+ .toHaveBeenLastCalledWith(
+ 'meal',
+ expect.anything(),
+ 'margarita'
+ )
})
```
+
您还可以使用快照:
```js
test('call the callback', () => {
// mockName 在 Jest 22+ 中可用
- const callback = jest.fn().mockName('Unicorn')
+ const callback = jest.fn()
+ .mockName('Unicorn')
+
fn(callback)
expect(callback).toMatchSnapshot()
// ->
@@ -506,6 +604,7 @@ const callback = jest.fn(() => true)
```js
const callback
= jest.fn().mockReturnValue(true)
+
const callbackOnce
= jest.fn().mockReturnValueOnce(true)
```
@@ -513,26 +612,29 @@ const callbackOnce
或解析值:
```js
-const promise
+const promise
= jest.fn().mockResolvedValue(true)
-const promiseOnce
+
+const promiseOnce
= jest.fn().mockResolvedValueOnce(true)
```
他们甚至可以拒绝值:
```js
-const failedPromise
- = jest.fn().mockRejectedValue('Error')
-const failedPromiseOnce
- = jest.fn().mockRejectedValueOnce('Error')
+const failedPromise =
+ jest.fn().mockRejectedValue('Error')
+
+const failedPromiseOnce =
+ jest.fn().mockRejectedValueOnce('Error')
```
你甚至可以结合这些:
```js
-const callback
- = jest.fn().mockReturnValueOnce(false).mockReturnValue(true)
+const callback = jest.fn()
+ .mockReturnValueOnce(false)
+ .mockReturnValue(true)
// ->
// call 1: false
// call 2+: true
@@ -541,13 +643,20 @@ const callback
### 使用 `jest.mock` 方法模拟模块
```js
-jest.mock('lodash/memoize', () => (a) => a) // The original lodash/memoize should exist
-jest.mock('lodash/memoize', () => (a) => a, { virtual: true }) // The original lodash/memoize isn’t required
+// 原来的 lodash/memoize 应该存在
+jest.mock(
+ 'lodash/memoize',
+ () => (a) => a
+)
+// 不需要原始的 lodash/memoize
+jest.mock(
+ 'lodash/memoize',
+ () => (a) => a,
+ { virtual: true }
+)
```
-[jest.mock docs](https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options)
-
-> 注意:当使用 `babel-jest` 时,对 `jest.mock` 的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 `jest.doMock`。
+注意:当使用 `babel-jest` 时,对 [`jest.mock`](https://jestjs.io/docs/en/jest-object#jestmockmodulename-factory-options) 的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 `jest.doMock`。
### 使用模拟文件模拟模块
@@ -563,22 +672,18 @@ module.exports = (a) => a
jest.mock('lodash/memoize')
```
-注意:当使用 `babel-jest` 时,对 `jest.mock` 的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 `jest.doMock`。
+注意:当使用 `babel-jest` 时,对 `jest.mock` 的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 `jest.doMock`。[手动模拟文档](https://jestjs.io/docs/en/manual-mocks)
-[手动模拟文档](https://jestjs.io/docs/en/manual-mocks)
-
-### 模拟对象方法
+### 模拟 getters 和 setters
```js
-const spy = jest.spyOn(console, 'log').mockImplementation(() => {})
-expect(console.log.mock.calls).toEqual([['dope'], ['nope']])
-spy.mockRestore()
-```
-
-```js
-const spy = jest.spyOn(ajax, 'request').mockImplementation(() => Promise.resolve({ success: true }))
-expect(spy).toHaveBeenCalled()
-spy.mockRestore()
+const getTitle = jest.fn(() => 'pizza')
+const setTitle = jest.fn()
+const location = {}
+Object.defineProperty(location, 'title', {
+ get: getTitle,
+ set: setTitle,
+})
```
### 模拟 getter 和 setter (Jest 22.1.0+)
@@ -603,8 +708,9 @@ const setTitle = jest
jest.useFakeTimers()
test('kill the time', () => {
const callback = jest.fn()
- // 运行一些使用 setTimeout 或 setInterval 的代码
- const actual = someFunctionThatUseTimers(callback)
+ // 运行使用 setTimeout或setInterval 的代码
+ const actual
+ = someFunctionThatUseTimers(callback)
// 快进直到所有定时器都执行完毕
jest.runAllTimers()
// 同步检查结果
@@ -619,8 +725,9 @@ test('kill the time', () => {
jest.useFakeTimers()
test('kill the time', () => {
const callback = jest.fn()
- // 运行一些使用 setTimeout 或 setInterval 的代码
- const actual = someFunctionThatUseTimers(callback)
+ // 运行使用 setTimeout或setInterval 的代码
+ const actual
+ = someFunctionThatUseTimers(callback)
// 快进 250 毫秒
jest.advanceTimersByTime(250)
// 同步检查结果
@@ -628,20 +735,29 @@ test('kill the time', () => {
})
```
-对于特殊情况,请使用 [jest.runOnlyPendingTimers()](https://jestjs.io/docs/en/timer-mocks#run-pending-timers)。
+> 对于特殊情况,请使用 [jest.runOnlyPendingTimers()](https://jestjs.io/docs/en/timer-mocks#run-pending-timers)。
**注意:** 您应该在测试用例中调用 `jest.useFakeTimers()` 以使用其他假计时器方法。
-### 模拟 getters 和 setters
+### 模拟对象方法
```js
-const getTitle = jest.fn(() => 'pizza')
-const setTitle = jest.fn()
-const location = {}
-Object.defineProperty(location, 'title', {
- get: getTitle,
- set: setTitle,
-})
+const spy = jest.spyOn(console, 'log')
+ .mockImplementation(() => {})
+
+expect(console.log.mock.calls)
+ .toEqual([['dope'], ['nope']])
+spy.mockRestore()
+```
+
+```js
+const spy = jest.spyOn(ajax, 'request')
+ .mockImplementation(
+ () => Promise.resolve({success: true})
+ )
+
+expect(spy).toHaveBeenCalled()
+spy.mockRestore()
```
### 清除和恢复模拟
@@ -653,8 +769,10 @@ Object.defineProperty(location, 'title', {
// 清除模拟使用日期
// (fn.mock.calls、fn.mock.instances)
fn.mockClear()
+
// 清除并删除任何模拟的返回值或实现
fn.mockReset()
+
// 重置并恢复初始实现
fn.mockRestore()
```
diff --git a/docs/package.json.md b/docs/package.json.md
index 7c85977..6c247cb 100644
--- a/docs/package.json.md
+++ b/docs/package.json.md
@@ -101,7 +101,7 @@ https://registry.npmjs.org/[包名]/-/[包名]-[version].tgz
鼓励使用开源 [(OSI-approved)](https://opensource.org/licenses/alphabetical) 许可证,除非你有特别的原因不用它。 如果你开发的包是你工作的一部分,最好和公司讨论后再做决定。
-**license字段必须是以下之一:**
+#### **license字段必须是以下之一**
- 如果你使用标准的许可证,需要一个有效地 [SPDX 许可证标识](https://spdx.org/licenses/)。
- 如果你用多种标准许可证,需要有效的 [SPDX 许可证表达式2.0语法表达式](https://www.npmjs.com/package/spdx)。
diff --git a/docs/styled-components.md b/docs/styled-components.md
new file mode 100644
index 0000000..7433096
--- /dev/null
+++ b/docs/styled-components.md
@@ -0,0 +1,1110 @@
+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(
+
+
+
+ {/*⚠️ 仍然可以使用Input中的 size attr*/}
+
+
+);
+```
+
+### 动画
+
+创建关键帧
+
+```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!
+
+);
+```
\ No newline at end of file
diff --git a/scripts/assets/styled-components.svg b/scripts/assets/styled-components.svg
new file mode 100644
index 0000000..5e15a08
--- /dev/null
+++ b/scripts/assets/styled-components.svg
@@ -0,0 +1,3 @@
+
diff --git a/scripts/style.css b/scripts/style.css
index dd6cfc8..24d7af9 100644
--- a/scripts/style.css
+++ b/scripts/style.css
@@ -212,7 +212,7 @@ table.show-header thead {
}
tt, code {
- font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
+ font-family: ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,monospace;
font-size: 1em;
}
pre:only-child {
@@ -222,7 +222,7 @@ pre:only-child {
pre {
margin-top: 0;
margin-bottom: 0;
- font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace;
+ font-family: ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,monospace;
word-wrap: normal;
line-height: 1.5;
overflow: hidden;