diff --git a/docs/docker.html b/docs/docker.html index cd6544e3..3d089429 100644 --- a/docs/docker.html +++ b/docs/docker.html @@ -49,11 +49,12 @@
docker/getting-started
- 要使用的镜像在前台创建并运行容器
-$ 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.html b/docs/jest.html
index 0b8e2d9d..0c98769c 100644
--- a/docs/jest.html
+++ b/docs/jest.html
@@ -150,6 +150,70 @@
expect(value).toThrow(error)
.toThrowErrorMatchingSnapshot()
+expect(value)
+ .toMatchSnapshot()
+ .toMatchInlineSnapshot()
+
+expect(value)
+ .toThrow(error)
+ .toThrowErrorMatchingSnapshot()
+
+expect(value)
+ .toBeInstanceOf(Class)
+ .toMatchObject(object)
+ .toHaveProperty(keyPath, value)
+
+expect(value)
+ .toContain(item)
+ .toContainEqual(item)
+ .toHaveLength(number)
+
+expect(value)
+ .toBeCloseTo(number, numDigits)
+ .toBeGreaterThan(number)
+ .toBeGreaterThanOrEqual(number)
+ .toBeLessThan(number)
+ .toBeLessThanOrEqual(number)
+
+expect(value)
+ .toBeFalsy()
+ .toBeNull()
+ .toBeTruthy()
+ .toBeUndefined()
+ .toBeDefined()
+
+expect(value)
+ .toMatch(regexpOrString)
+
+test('当值为 NaN 时通过', () => {
+ expect(NaN).toBeNaN();
+ expect(1).not.toBeNaN();
+});
+
+expect.extend(matchers)
+expect.any(constructor)
+expect.addSnapshotSerializer(serializer)
+
+expect.assertions(1)
+
expect(42).toBe(42) // 严格相等 (===)
@@ -291,7 +355,7 @@
// 匹配除 null 或 undefined 之外的任何内容
expect('pizza').toEqual(expect.anything())
-// 这可确保某个值与最近的快照匹配。
expect(node).toMatchSnapshot()
@@ -360,7 +424,6 @@
请参阅 Jest 文档中的 更多示例。
在异步测试中指定一些预期的断言是一个很好的做法,所以如果你的断言根本没有被调用,测试将会失败。
test('async test', () => {
// 在测试期间恰好调用了三个断言
@@ -373,7 +436,8 @@
请注意,您也可以在任何 describe
和 test
之外对每个文件执行此操作:
beforeEach(expect.hasAssertions)
-这将验证每个测试用例至少存在一个断言。 它还可以与更具体的 expect.assertions(3)
声明配合使用。
+这将验证每个测试用例至少存在一个断言。 它还可以与更具体的 expect.assertions(3)
声明配合使用。
+请参阅 Jest 文档中的 更多示例
test('async test', async () => {
expect.assertions(1)
@@ -391,8 +455,8 @@
setTimeout(() => {
try {
- const result = getAsyncOperationResult()
- expect(result).toBe(true)
+ const res = getAsyncOperatResult()
+ expect(res).toBe(true)
done()
} catch (err) {
done.fail(err)
@@ -414,19 +478,29 @@
test('call the callback', () => {
+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'
+ )
})
+
您还可以使用快照:
test('call the callback', () => {
// mockName 在 Jest 22+ 中可用
- const callback = jest.fn().mockName('Unicorn')
+ const callback = jest.fn()
+ .mockName('Unicorn')
+
fn(callback)
expect(callback).toMatchSnapshot()
// ->
@@ -444,36 +518,46 @@
您的模拟可以返回值:
const callback
= jest.fn().mockReturnValue(true)
+
const callbackOnce
= jest.fn().mockReturnValueOnce(true)
或解析值:
-const promise
+const promise
= jest.fn().mockResolvedValue(true)
-const promiseOnce
+
+const promiseOnce
= jest.fn().mockResolvedValueOnce(true)
他们甚至可以拒绝值:
-const failedPromise
- = jest.fn().mockRejectedValue('Error')
-const failedPromiseOnce
- = jest.fn().mockRejectedValueOnce('Error')
+const failedPromise =
+ jest.fn().mockRejectedValue('Error')
+
+const failedPromiseOnce =
+ jest.fn().mockRejectedValueOnce('Error')
你甚至可以结合这些:
-const callback
- = jest.fn().mockReturnValueOnce(false).mockReturnValue(true)
+const callback = jest.fn()
+ .mockReturnValueOnce(false)
+ .mockReturnValue(true)
// ->
// call 1: false
// call 2+: true
jest.mock
方法模拟模块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 }
+)
-
-
-注意:当使用 babel-jest
时,对 jest.mock
的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 jest.doMock
。
-
+注意:当使用 babel-jest
时,对 jest.mock
的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 jest.doMock
。
创建一个类似 __mocks__/lodash/memoize.js
的文件:
module.exports = (a) => a
@@ -481,16 +565,15 @@
添加到您的测试中:
jest.mock('lodash/memoize')
-注意:当使用 babel-jest
时,对 jest.mock
的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 jest.doMock
。
-
-
const spy = jest.spyOn(console, 'log').mockImplementation(() => {})
-expect(console.log.mock.calls).toEqual([['dope'], ['nope']])
-spy.mockRestore()
-
-const spy = jest.spyOn(ajax, 'request').mockImplementation(() => Promise.resolve({ success: true }))
-expect(spy).toHaveBeenCalled()
-spy.mockRestore()
+注意:当使用 babel-jest
时,对 jest.mock
的调用将自动提升到代码块的顶部。 如果您想明确避免这种行为,请使用 jest.doMock
。手动模拟文档
+
const getTitle = jest.fn(() => 'pizza')
+const setTitle = jest.fn()
+const location = {}
+Object.defineProperty(location, 'title', {
+ get: getTitle,
+ set: setTitle,
+})
const location = {}
@@ -508,8 +591,9 @@
jest.useFakeTimers()
test('kill the time', () => {
const callback = jest.fn()
- // 运行一些使用 setTimeout 或 setInterval 的代码
- const actual = someFunctionThatUseTimers(callback)
+ // 运行使用 setTimeout或setInterval 的代码
+ const actual
+ = someFunctionThatUseTimers(callback)
// 快进直到所有定时器都执行完毕
jest.runAllTimers()
// 同步检查结果
@@ -521,24 +605,34 @@
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)
// 同步检查结果
expect(callback).toHaveBeenCalledTimes(1)
})
+对于特殊情况,请使用 jest.runOnlyPendingTimers()。
+
注意: 您应该在测试用例中调用 jest.useFakeTimers()
以使用其他假计时器方法。
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()
+
+const spy = jest.spyOn(ajax, 'request')
+ .mockImplementation(
+ () => Promise.resolve({success: true})
+ )
+
+expect(spy).toHaveBeenCalled()
+spy.mockRestore()
// 清除模拟使用日期
// (fn.mock.calls、fn.mock.instances)
fn.mockClear()
+
// 清除并删除任何模拟的返回值或实现
fn.mockReset()
+
// 重置并恢复初始实现
fn.mockRestore()
diff --git a/docs/package.json.html b/docs/package.json.html
index bfb2f968..9f384203 100644
--- a/docs/package.json.html
+++ b/docs/package.json.html
@@ -102,14 +102,14 @@
}
鼓励使用开源 (OSI-approved) 许可证,除非你有特别的原因不用它。 如果你开发的包是你工作的一部分,最好和公司讨论后再做决定。
-license字段必须是以下之一:
+SEE LICENSE IN <文件名>
字符串指向你的包里顶级目录的一个 <文件名>。UNLICENSED
字符串。keywords
keywords
{
"keywords": [
"short", "relevant", "keywords"
diff --git a/docs/styled-components.html b/docs/styled-components.html
new file mode 100644
index 00000000..733593b1
--- /dev/null
+++ b/docs/styled-components.html
@@ -0,0 +1,962 @@
+
+
+
+
+styled-components 备忘清单
+ & styled-components cheatsheet & Quick Reference
+
+
+
+
+
+
+
styled-components 备忘清单
+此快速参考备忘单提供了使用 CSS in JS 工具的各种方法。
+
入门
+
安装
+Styled Components 是增强 CSS 在 React 组件系统样式的 CSS in JS 的最佳实践。
+
+- VSCode styled-components 有代码高亮和代码提示
+- VIM styled-components 有代码高亮
+- WebStorm styled-components 有代码高亮和代码提示
+
+安装依赖和 TypeScript 类型依赖
+npm install --save styled-components
+
+
快速开始
+
+import styled from 'styled-components';
+
+创建一个 Title 组件
+// 该组件将呈现具有样式的 <h1> 标签
+const Title = styled.h1`
+ font-size: 1.5em;
+ text-align: center;
+`;
+
+创建一个 Wrapper 组件
+// 该组件将呈现具有某些样式的 <section> 标记
+const Wrapper = styled.section`
+ padding: 4em;
+ background: papayawhip;
+`;
+
+像使用其他 React 组件一样使用 Title/Wrapper - 除了它们的样式!
+function Demo() {
+ return (
+ <Wrapper>
+ <Title>
+ Hello World!
+ </Title>
+ </Wrapper>
+ );
+}
+
+
根据 Props 适配
+
+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 控制按钮样式
+function Demo() {
+ return (
+ <div>
+ <Button>Normal</Button>
+ <Button primary>Primary</Button>
+ </div>
+ );
+}
+
+
扩展样式
+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 = () => (
+ <div>
+ <Button>普通按钮</Button>
+ <TomatoButton>番茄色按钮</TomatoButton>
+ </div>
+);
+
+
扩展样式改变标签 (as)
+
+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 = () => (
+ <div>
+ <Button>普通按钮</Button>
+ <Button as="a" href="#">
+ 按钮样式的链接
+ </Button>
+ <TomatoButton as="a" href="#">
+ 番茄按钮样式的链接
+ </TomatoButton>
+ </div>
+);
+
+
自定义组件(as)
+
+const Button = styled.button`
+ color: palevioletred;
+ font-size: 1em;
+ border: 2px solid palevioletred;
+ display: block;
+`;
+
+const ReversedButton = props => (
+ <Button
+ {...props}
+ children={
+ props.children.split('').reverse()
+ }
+ />
+);
+
+render(
+ <div>
+ <Button>普通按钮</Button>
+ <Button as={ReversedButton}>
+ 具有普通按钮样式的自定义按钮
+ </Button>
+ </div>
+);
+
+
样式化任何组件
+const Link = ({ className, children }) => (
+ <a className={className}>
+ {children}
+ </a>
+);
+const StyledLink = styled(Link)`
+ color: palevioletred;
+ font-weight: bold;
+`;
+<StyledLink className="hello" />
+
+
在 render 之外定义 Styled 组件
+
+const Box = styled.div`/* ... */`;
+const Wrapper = ({ message }) => {
+ // ⚠️ 不能在这里定义 styled 组件
+ return (
+ <Box>
+ {message}
+ </Box>
+ );
+};
+
+注意:组件 Box
不能放到 Wrapper
函数组件里面
+
传入值
+const Input = styled.input`
+ color: ${
+ props =>
+ props.inputColor || "palevioletred"
+ };
+ background: papayawhip;
+`;
+const Demo = () => (
+ <div>
+ <Input
+ defaultValue="@probablyup"
+ type="text"
+ />
+ <Input
+ defaultValue="@geelen"
+ type="text"
+ inputColor="rebeccapurple"
+ />
+ </div>
+);
+
+
样式对象
+const PropsBox = styled.div(props => ({
+ background: props.background,
+ height: '50px',
+ width: '50px',
+ fontSize: '12px'
+}));
+
+在组件中使用
+const Example = () => {
+ return (
+ <div>
+ <PropsBox
+ background="blue"
+ />
+ </div>
+ );
+}
+
+注意:样式对象里面的样式并不是 CSS 中的写法。
+
CSSModules => styled
+
+import React, { useState } from 'react';
+import styles from './styles.css';
+
+function ExampleCounter() {
+ const [count, setCount] = useState(0)
+ return (
+ <div className={styles.counter}>
+ <p className={styles.paragraph}>
+ {count}
+ </p>
+ <button
+ className={styles.button}
+ onClick={() => setCount(count +1)}
+ >
+ +
+ </button>
+ <button
+ className={styles.button}
+ onClick={() => setCount(count -1)}
+ >
+ -
+ </button>
+ </div>
+ );
+}
+
+
👇👇 与下面 styled 写法等效 👇👇
+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 (
+ <StyledCounter>
+ <Paragraph>{count}</Paragraph>
+ <Button onClick={increment}>
+ +
+ </Button>
+ <Button onClick={decrement}>
+ -
+ </Button>
+ </StyledCounter>
+ );
+}
+
+
伪元素、伪选择器和嵌套
+
+const Thing = styled.div.attrs((/* props */) => ({ tabIndex: 0 }))`
+ color: blue;
+ &:hover { /* <Thing> 悬停时 */
+ color: red;
+ }
+ & ~ & { /* <Thing> 作为 <Thing> 的兄弟,但可能不直接在它旁边 */
+ background: tomato;
+ }
+ & + & { /* <Thing> 旁边的 <Thing> */
+ background: lime;
+ }
+ &.something { /* <Thing> 标记有一个额外的 CSS 类 “.something” */
+ background: orange;
+ }
+ .something-else & { /* <Thing> 在另一个标记为 “.something-else” 的元素中 */
+ border: 1px solid;
+ }
+`;
+
+render(
+ <React.Fragment>
+ <Thing>Hello world!</Thing>
+ <Thing>你怎么样?</Thing>
+ <Thing className="something">
+ 艳阳高照...
+ </Thing>
+ <div>今天真是美好的一天。</div>
+ <Thing>你不觉得吗?</Thing>
+ <div className="something-else">
+ <Thing>灿烂</Thing>
+ </div>
+ </React.Fragment>
+);
+
+
改变 styled 组件样式
+
+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 (
+ <React.Fragment>
+ <Label>
+ <Input defaultChecked />
+ <LabelText>Foo</LabelText>
+ </Label>
+ <Label>
+ <Input />
+ <LabelText $mode="dark">
+ Foo
+ </LabelText>
+ </Label>
+ </React.Fragment>
+ );
+}
+
+
全局样式 createGlobalStyle
+import {
+ styled,
+ createGlobalStyle
+} from 'styled-components'
+
+const Thing = styled.div`
+ && {
+ color: blue;
+ }
+`;
+const GlobalStyle = createGlobalStyle`
+ div${Thing} {
+ color: red;
+ }
+`;
+
+const Example = () => (
+ <React.Fragment>
+ <GlobalStyle />
+ <Thing>
+ 我是蓝色的
+ </Thing>
+ </React.Fragment>
+);
+
+
className 使用
+const Thing = styled.div`
+ color: blue;
+ /* <Thing> 中标记为“.something”的元素 */
+ .something {
+ border: 1px solid;
+ }
+`;
+
+function Example() {
+ return (
+ <Thing>
+ <label
+ htmlFor="foo-button"
+ className="something"
+ >
+ 神秘按钮
+ </label>
+ <button id="foo-button">
+ 我该怎么办?
+ </button>
+ </Thing>
+ )
+}
+
+
共享样式片段
+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 组件样式定义
+class NewHeader extends React.Component {
+ render() {
+ return (
+ <div
+ className={this.props.className}
+ />
+ );
+ }
+}
+const StyledA = styled(NewHeader)``
+const Box = styled.div`
+ ${StyledA} {
+ /* 变更 NewHeader 样式 */
+ }
+`;
+
+
附加额外的 Props
+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
组件
+function Example() {
+ return (
+ <div>
+ <Input placeholder="小文本输入" />
+ <br />
+ <Input
+ placeholder="更大的文本输入"
+ size="2em"
+ />
+ </div>
+ )
+}
+
+
覆盖 .attrs
+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
组件
+render(
+ <div>
+ <Input
+ placeholder="更大的文本输入"
+ size="2em"
+ />
+ <br />
+ {/*⚠️ 仍然可以使用Input中的 size attr*/}
+ <PasswordInput
+ placeholder="更大的密码输入"
+ size="2em"
+ />
+ </div>
+);
+
+
动画
+创建关键帧
+const rotate = keyframes`
+ from {
+ transform: rotate(0deg);
+ }
+
+ to {
+ transform: rotate(360deg);
+ }
+`;
+
+我们创建一个 Rotate
组件
+// 它将在两秒内旋转我们传递的所有内容
+const Rotate = styled.div`
+ display: inline-block;
+ animation: ${rotate} 2s linear infinite;
+ padding: 2rem 1rem;
+ font-size: 1.2rem;
+`;
+
+使用 Rotate
组件
+function Example() {
+ return (
+ <Rotate>< 💅🏾 ></Rotate>
+ )
+}
+
+
isStyledComponent
+
+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
+import {
+ ThemeConsumer
+} from 'styled-components'
+
+function Example() {
+ return (
+ <ThemeConsumer>
+ {theme => (
+ <div>主题色是 {theme.color}</div>
+ )}
+ </ThemeConsumer>
+ );
+}
+
+
TypeScript
+
安装
+Web 应用上安装 styled
+npm install -D @types/styled-components
+
+React Native 应用上安装 styled
+npm install -D \
+ @types/styled-components \
+ @types/styled-components-react-native
+
+如果对 TypeScript 不熟悉,参考 TypeScript 备忘清单
+
自定义 Props
+import styled from 'styled-components';
+
+interface TitleProps {
+ readonly isActive: boolean;
+}
+
+const Title = styled.h1<TitleProps>`
+ color: ${(props) => (
+ props.isActive
+ ? props.theme.colors.main
+ : props.theme.colors.secondary
+ )};
+`;
+
+
简单的 Props 类型定义
+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};
+`;
+
+
禁止转移到子组件($)
+import styled from 'styled-components';
+import Header from './Header';
+
+interface ReHeader {
+ $customColor: string;
+}
+
+const ReHeader = styled(Header)<ReHeader>`
+ color: ${
+ props => props.$customColor
+ };
+`;
+
+禁止 customColor
属性转移到 Header
组件,在其前面加上美元($
)符号
+
函数组件类型继承
+
+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>, HTMLImageElement
+> {
+ text?: string;
+};
+export const Image: FC<PropsWithRef<ImageProps>> = (props) => (
+ <Img src="" alt="" {...props} />
+);
+
+
React Native
+
+
基础实例
+
+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 (
+ <StyledView>
+ <StyledText>Hello World!</StyledText>
+ </StyledView>
+ );
+ }
+}
+
+
React Native 中写 CSS
+
+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 (
+ <RotatedBox />
+ )
+}
+
+与 web 版本的一些区别是,您不能使用关键帧(keyframes
)和 createGlobalStyle
助手,因为 React Native 不支持关键帧或全局样式。如果您使用媒体查询或嵌套 CSS,我们也会警告您。
+
高级用法
+
+
主题化
+
+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(
+ <div>
+ <Button>Normal</Button>
+
+ <ThemeProvider theme={theme}>
+ <Button>Themed</Button>
+ </ThemeProvider>
+ </div>
+);
+
+
功能主题
+
+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(
+ <ThemeProvider theme={theme}>
+ <div>
+ <Button>默认主题</Button>
+ <ThemeProvider theme={invertTheme}>
+ <Button>反转主题</Button>
+ </ThemeProvider>
+ </div>
+ </ThemeProvider>
+);
+
+
通过 withTheme 高阶组件
+
+import { withTheme } from 'styled-components'
+
+class MyComponent extends React.Component {
+ render() {
+ console.log('Current theme: ', this.props.theme)
+ // ...
+ }
+}
+
+export default withTheme(MyComponent)
+
+
useContext 钩子
+
+import { useContext } from 'react'
+import { ThemeContext } from 'styled-components'
+
+const MyComponent = () => {
+ const themeContext = useContext(ThemeContext)
+
+ console.log('Current theme: ', themeContext)
+ // ...
+}
+
+
useTheme 自定义钩子
+
+import {useTheme} from 'styled-components'
+
+const MyComponent = () => {
+ const theme = useTheme()
+
+ console.log('Current theme: ', theme)
+ // ...
+}
+
+
主题 props
+
+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"
+};
+
+使用自定义主题组件
+render(
+ <div>
+ <Button theme={{ main: "royalblue" }}>
+ 特设主题
+ </Button>
+ <ThemeProvider theme={theme}>
+ <div>
+ <Button>Themed</Button>
+ <Button
+ theme={{ main: "darkorange" }}
+ >
+ 被覆盖
+ </Button>
+ </div>
+ </ThemeProvider>
+ </div>
+);
+
+
Refs
+
+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 (
+ <Input
+ ref={this.inputRef}
+ placeholder="Hover to focus!"
+ onMouseEnter={() => {
+ this.inputRef.current.focus()
+ }}
+ />
+ );
+ }
+}
+
+使用 Form
组件
+function Example() {
+ return (
+ <Form />
+ )
+}
+
+
特异性问题
+
+在文件 MyComponent.js
中定义 MyComponent
组件。
+const MyComponent = styled.div`
+ background-color: green;
+`;
+
+定义样式 my-component.css
+.red-bg {
+ background-color: red;
+}
+
+使用 MyComponent
组件
+<MyComponent className="red-bg" />
+
+由于某种原因,这个组件仍然有绿色背景,即使你试图用 red-bg
类覆盖它!
+
解决方案
+.red-bg.red-bg {
+ background-color: red;
+}
+
+
ThemeProvider
+
+import styled, { ThemeProvider } from 'styled-components'
+
+const Box = styled.div`
+ color: ${props => props.theme.color};
+`;
+
+const Example = () => (
+ <ThemeProvider theme={{ color: 'mediumseagreen' }}>
+ <Box>I'm mediumseagreen!</Box>
+ </ThemeProvider>
+);
+
+
shouldForwardProp
+
+const Comp = styled('div').withConfig({
+ shouldForwardProp: (prop, defaultValidatorFn) =>
+ !['hidden'].includes(prop) && defaultValidatorFn(prop),
+}).attrs({ className: 'foo' })`
+ color: red;
+ &.foo {
+ text-decoration: underline;
+ }
+`;
+
+const Example = () => (
+ <Comp hidden draggable="true">
+ Drag Me!
+ </Comp>
+);
+
+
+
diff --git a/index.html b/index.html
index 7c77d2ed..80473ec3 100644
--- a/index.html
+++ b/index.html
@@ -67,6 +67,10 @@
React
+
+Styled Components