likes
comments
collection
share

(01)Header 组件开发——① “项目初建”和“styled-components 初识” | React.js 项目实战:PC 端“简书”开发

作者站长头像
站长
· 阅读数 4
转载请注明出处,未经同意,不可修改文章内容。

🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。

1 项目初建

根据之前的“React.js 基础语法学习”中的内容,我们先自行对照文章:

进行项目( qdywxs-jianshu )的新建及代码精简。

此刻你的“代码结构”和“最终页面效果”应该是如下图所示: (01)Header 组件开发——① “项目初建”和“styled-components 初识” | React.js 项目实战:PC 端“简书”开发

(01)Header 组件开发——① “项目初建”和“styled-components 初识” | React.js 项目实战:PC 端“简书”开发

2 styled-components 初识

2.1 为什么使用 styled-components

按照惯性思维,如果我们要给某个组件增加“样式”的话,一般都是如下的步骤:

1️⃣首先,在 src 目录下新建一个 index.css 文件:

body {
  margin: 0;
  padding: 0;
  font-family: san-serif;
}

.content {
  background: red;
}

2️⃣其次,打开 src 目录下的 App.js 文件。给 div 绑定一个 class 名:

import React, { Component } from "react";

class App extends Component  {  
  
  render() {  
    return (  
      <div className="content">  
        hello, qdywxs.
      </div>  
    );
  }
}

export default App; 

3️⃣然后,打开 src 目录下的 index.js 文件。在其顶部引入 index.js 文件:

import React from 'react';
import ReactDOM from 'react-dom';

// ❗️引入 index.css 文件!
import "./index.css"

import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

返回页面查看: (01)Header 组件开发——① “项目初建”和“styled-components 初识” | React.js 项目实战:PC 端“简书”开发

OK,上边的一通操作不知大家是否发现了一个问题:

src 目录下的 index.js 文件是整个程序的入口文件,我们在这个 JS 文件里引入一个 CSS 文件。

这好像没什么不对?

我们单单是在 index.js 文件中引入了 index.css ,其并没有在“组件 App.js ”中引入 index.css 。可为什么最后的页面显示了这个“样式”呢?

是不是可以发现,其实任何“组件”的任何元素只要加了 className="content"; ,即使它没在本“组件”的顶部引入 index.css ,它都会显示这个“样式”!

即,CSS 文件一旦在一个文件里被引入,那整个程序“全局”都会生效!

CSS 的规则都是全局的,任何一个组件的样式规则,都对整个页面有效。

❌产生的问题:当页面内容很多——这个“组件”有一堆 CSS,那个“组件”又有一堆 CSS。当这些 CSS 都被放入一个文件里被引入进来时,就会导致“组件”间 CSS 样式“冲突”的可能。

✔️我们希望:在写项目的时候,每一个“组件”的“样式”都是独立的,不要去互相影响。故,我们不建议在项目中直接去引入 CSS“样式”。但想要产生“局部作用域”,其唯一方法就是使用一个独一无二的 class  名字,不会与其他选择器重名。

在 React 中,业内比较推崇使用强大的第三方模块 styled-components 来解决“CSS 样式全局污染”这个痛点,并对“样式”进行管理!

2.2 怎样使用 styled-components

1️⃣命令行定位到 qdywxs-jianshu 文件,安装 styled-components:

npm install --save styled-components

2️⃣然后将 src 目录下的 index.css 文件改名为 style.js 文件(即,将“样式”放在一个 JS 文件中来编写): (01)Header 组件开发——① “项目初建”和“styled-components 初识” | React.js 项目实战:PC 端“简书”开发

3️⃣打开 style.js 文件,我们来对之前的“样式”进行改写:

/*
❗️注释掉之前的 CSS 样式!
body {
  margin: 0;
  padding: 0;
  font-family: san-serif;
}

.content {
  background: red;
}
 */

// 4️⃣我们先对 body 这个“全局”样式进行改写;
/*
4️⃣-①:对于“全局”样式,styled-components 有特殊的写法。
首先,从 styled-components 中引入 createGlobalStyle 这个方法!
 */
import {createGlobalStyle} from "styled-components";

/*
4️⃣-②:然后,创建一个 GlobalStyle “样式组件”,并将 createGlobalStyle 方法包裹(
用 ES6 语法中的 `` 进行包裹)的“全局样式”赋值给 GlobalStyle!
 */
export const GlobalStyle = createGlobalStyle`
  body {
    margin: 0;
    padding: 0;
    font-family: san-serif;

    background: green;  
  }
`;
// ❗️为了测试是否样式生效,我们加一个“全局”的背景色!

5️⃣打开 src 目录下的 index.js 文件:

import React from 'react';
import ReactDOM from 'react-dom';

/*
❗️删除掉这里对 CSS 样式的引入!
import "./index.css"
 */

import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

6️⃣打开 src 目录下的 App.js 文件:

import React, { Component } from "react";

// ❗️6️⃣-①:首先,引入第 4️⃣-② 步定义的 GlobalStyle;
import {GlobalStyle} from "./style";

class App extends Component  {  
  
  render() {  
    
    /*
    ❗️❗️❗️6️⃣-②:然后将 <GlobalStyle /> 放在 render() 中最外层元素下面!
    这样后面的所有元素“组件”都应用了 GlobalStyle 中定义的“全局”样式。
     */
    return (
      <div>
      	<GlobalStyle />
        <div> 
          hello, qdywxs.
        </div>  
      </div>
    );
  }
}

export default App; 

返回页面查看效果(用 styled-components 改写的“全局”样式成功显示): (01)Header 组件开发——① “项目初建”和“styled-components 初识” | React.js 项目实战:PC 端“简书”开发

3 reset.css 和 common.css 的使用

在正式开始编写 qdywxs-jianshu 项目之前,我们首先要做的事依然是——让默认样式在所有浏览器上做到“统一”。

1️⃣打开 rest.css 官网,拷贝相应代码:

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
	display: block;
}
body {
	line-height: 1;
}
ol, ul {
	list-style: none;
}
blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}
table {
	border-collapse: collapse;
	border-spacing: 0;
}

2️⃣打开 src 目录下的 styled.js 文件:

import {createGlobalStyle} from "styled-components";

// 3️⃣将 rest.css 中的代码拷贝到这个“全局”样式中!
export const GlobalStyle = createGlobalStyle`
  html, body, div, span, applet, object, iframe,
  h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  a, abbr, acronym, address, big, cite, code,
  del, dfn, em, img, ins, kbd, q, s, samp,
  small, strike, strong, sub, sup, tt, var,
  b, u, i, center,
  dl, dt, dd, ol, ul, li,
  fieldset, form, label, legend,
  table, caption, tbody, tfoot, thead, tr, th, td,
  article, aside, canvas, details, embed, 
  figure, figcaption, footer, header, hgroup, 
  menu, nav, output, ruby, section, summary,
  time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
  }
  /* HTML5 display-role reset for older browsers */
  article, aside, details, figcaption, figure, 
  footer, header, hgroup, menu, nav, section {
    display: block;
  }
  body {
    line-height: 1;
  }
  ol, ul {
    list-style: none;
  }
  blockquote, q {
    quotes: none;
  }
  blockquote:before, blockquote:after,
  q:before, q:after {
    content: '';
    content: none;
  }
  table {
    border-collapse: collapse;
    border-spacing: 0;
  }
`;

4️⃣顺便,将我们“简书”这个项目自己会有的一些 common 样式也加入到 GlobalStyle 样式组件中:

import {createGlobalStyle} from "styled-components";

export const GlobalStyle = createGlobalStyle`
  html, body, div, span, applet, object, iframe,
  h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  a, abbr, acronym, address, big, cite, code,
  del, dfn, em, img, ins, kbd, q, s, samp,
  small, strike, strong, sub, sup, tt, var,
  b, u, i, center,
  dl, dt, dd, ol, ul, li,
  fieldset, form, label, legend,
  table, caption, tbody, tfoot, thead, tr, th, td,
  article, aside, canvas, details, embed, 
  figure, figcaption, footer, header, hgroup, 
  menu, nav, output, ruby, section, summary,
  time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
  }
  /* HTML5 display-role reset for older browsers */
  article, aside, details, figcaption, figure, 
  footer, header, hgroup, menu, nav, section {
    display: block;
  }
  body {
    line-height: 1;
  }
  ol, ul {
    list-style: none;
  }
  blockquote, q {
    quotes: none;
  }
  blockquote:before, blockquote:after,
  q:before, q:after {
    content: '';
    content: none;
  }
  table {
    border-collapse: collapse;
    border-spacing: 0;
  }


  /* ❗️5️⃣以下为我们“简书”项目自己的一些 common 样式! */
  * {
  margin: 0;
  padding: 0;
  box-sizing: border-box;

  }

  a {
    text-decoration: none;
  }

  ul {
    list-style: none;
  }

  body {
    font: 13px/1.8 -apple-system, 'SF UI Text',Arial,'PingFang SC','Hiragino Sans GB','Microsoft YaHei','WenQuanYi Micro Hei',sans-serif;
    /* 哪里的字最多,我们就把这个字体设为通用样式。 */

    color: #444;
  }

  .clearfix:after {
    content: "";
    display: block;
    clear: both;
  }


  .layout {
    width: 950px;
    margin-left: auto;
    margin-right: auto;
  }
  /*
  这几行代码是为了水平”居中“,但在通用样式里边,我们一般不要去设 margin-top 的值,
  因为后边如果特定样式需要设置这个值,我们再单独拿出来设置就可以了。
   */

`;

返回页面查看效果(未报错): (01)Header 组件开发——① “项目初建”和“styled-components 初识” | React.js 项目实战:PC 端“简书”开发

🚀在开始下一篇文章之前,请至少阅读一次以下官方文档翻译版(请对照官网英文原版和官方效果阅读和学习~)!

祝好,qdywxs ♥ you!

附录

🔗styled-componnets 官方文档——基础部分

1 动机

styled-components 是作者对于如何增强 React 组件中 CSS 表现这个问题的思考结果。 通过聚焦于单个用例,设法优化了开发者的体验和面向终端用户的输出。

除了提升开发者体验外, styled-components 同时提供以下特性:

  • Automatic critical CSS: styled-components 持续跟踪页面上渲染的组件,并向自动其注入且仅注入样式。结合使用代码拆分, 可以实现仅加载所需的最少代码。
  • 解决了 class name 冲突: styled-components 为样式生成唯一的 class name。开发者不必再担心 class name 重复,覆盖和拼写错误的问题。
  • CSS 更容易移除: 想要确切的知道代码中某个 class 在哪儿用到是很困难的。 使用 styled-components 则很轻松, 因为每个样式都有其关联的组件。如果检测到某个组件未使用并且被删除,则其所有的样式也都被删除。
  • 简单的动态样式: 可以很简单直观的实现根据组件的 props 或者全局主题适配样式,无需手动管理数十个 classes。
  • 无痛维护: 无需搜索不同的文件来查找影响组件的样式。无论代码多庞大,维护起来都是小菜一碟。
  • 自动提供前缀: 按照当前标准写 CSS,其余的交给 styled-components handle 处理。

通过 styled-components 绑定样式到组件,开发者可以在编写熟知的 CSS 同时也获得上述全部的益处。

2 安装

从 npm 安装 styled-components:

npm install --save styled-components

强烈推荐使用 styled-components 的 babel 插件 (当然这不是必须的)。它提供了许多益处,比如更清晰的类名,SSR 兼容性,更小的包等等。

如果没有使用模块管理工具或者包管理工具,也可以使用官方托管在 unpkg CDN 上的构建版本。只需在HTML文件底部添加以下 <script> 标签:

<script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>

添加 styled-components 之后就可以访问全局的 window.styled 变量。

const Component = window.styled.div`
  color: red;
`

❗️注意: 这用使用方式需要页面在 styled-components script 之前引入 react CDN bundles

3 入门

styled-components 通过标记的模板字符来设置组件样式。

它移除了组件和样式之间的映射。当我们通过 styled-components 定义样式时,我们实际上是创建了一个附加了样式的常规 React 组件。

以下的例子创建了两个简单的附加了样式的组件, 一个 Wrapper 和一个 Title

// 创建一个 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-components 会为我们自动创建 CSS 前缀。

4 基于属性的适配

我们可以将 props 以插值的方式传递给 styled component ,以调整组件样式。

下面这个 Button 组件持有一个可以改变 colorprimary 属性。将其设置为 ture 时,组件的 background-colorcolor 会交换。

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>
);

5 样式继承

可能我们希望某个经常使用的组件,在特定场景下可以稍微更改其样式。当然我们可以通过 props 传递插值的方式来实现,但是对于某个只需要重载一次的样式来说这样做的成本还是有点高。

创建一个继承其它组件样式的新组件,最简单的方式就是用构造函数 styled() 包裹被继承的组件。下面的示例就是通过继承上一节创建的按钮从而实现一些颜色相关样式的扩展:

// 上一节创建的没有插值的 Button 组件;
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>
);

可以看到,新的 TomatoButton 仍然和 Button 类似,我们只是添加了两条规则。

In some cases you might want to change which tag or component a styled component renders. 这在构建导航栏时很常见,例如导航栏中同时存在链接和按钮,但是它们的样式应该相同。

在这种情况下,我们也有替代办法(escape hatch)我们可以使用多态 "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>
);

6 给任何组件添加样式

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>
    

    <StyledLink>Styled, exciting Link</StyledLink>
  </div>
);

❗️注意: 也可以传递标签给 styled() , 比如: styled("div") 。实际上 styled.tagname 的方式就是 styled(tagname) 的别名。

7 属性传递

如果添加样式的目标是 DOM 元素 (如 styled.div ),styled-components 会传递已知的 HTML 属性给 DOM。如果是一个自定义的 React 组件(如 styled(MyComponent)),styled-components 会传递全部 props

以下示例展示如何传递 Input 组件的 props 到已装载的 DOM 节点, as with React elements。

// 创建一个给 <input> 标签添加若干样式的 Input 组件;
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, 但是 typedefaultValue 都传递了。 styled-components 足够智能,会自动过滤掉所有非标准 attribute。

8 Coming from CSS

8.1 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”前缀,这样组件 CounterStyledCounter 不会明明冲突,而且可以在 React Developer Tools 和 Web Inspector 中轻松识别。

8.2 在 render 方法之外定义 Styled Components

在 render 方法之外定义 styled component 很重要,不然 styled component 会在每个渲染过程中重新创建。这将阻止缓存生效并且大大降低了渲染速度,所以尽量避免这种情况。

推荐通过以下方式创建 styled components:

const StyledWrapper = styled.div`
  /* ... */
`

const Wrapper = ({ message }) => {
  return <StyledWrapper>{message}</StyledWrapper>
}

而不是:

const Wrapper = ({ message }) => {
  // ❗️注意:别这么干,会很慢!
  const StyledWrapper = styled.div`
    /* ... */
  `

  return <StyledWrapper>{message}</StyledWrapper>
}

推荐阅读Talia Marcassa 写了一篇很精彩的有关 styled-components 实际应用的文章,包含许多实用的见解以及与其它方案的比较 Styled Components: To Use or Not to Use?

8.3 伪元素,伪类选择器和嵌套

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>
)

9 附加额外的属性(v2)

为了避免仅为传递一些props来渲染组件或元素而使用不必要的 wrapper, 可以使用 .attrs constructor 。通过它可以添加额外的 props 或 attributes 到组件。

举例来说,可以通过这种方式给元素添加静态 props,或者传递第三方 prop 给组件(比如传递 activeClassName 给 React Router 的 Link)。此外也可以将 dynamic props 添加到组件。.attrs 对象也接收函数,返回值也将合并进 props。

示例如下:

const Input = styled.input.attrs({
  //  static props
  type: "password"

  //  dynamic props
  margin: 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" />
    

    <Input placeholder="A bigger text input" size="2em" />
  </div>
);

正如所见,我们可以在插值中访问新创建的 props,type attribute 也正确的传递给了元素。

10 动画

虽然使用 @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;
`;

❗️注意: react-native 不支持 keyframes,请参考ReactNative.Animated API

Keyframes are lazily injected when they're used, which is how they can be code-splitted, so you have to use the css helper for shared style fragments:

const rotate = keyframes``

// ❌ This will throw an error!
const styles = `
  animation: ${rotate} 2s linear infinite;
`;

// ✅ This will work as intended
const styles = css`
  animation: ${rotate} 2s linear infinite;
`

NOTE This used to work in v3 and below where we didn't code-split keyframes. If you're upgrading from v3, make sure that all your shared style fragments are using the css helper!

11 ReactNative

styled-components 可以在 React-Native 中以同样的方式使用。示例: Snack by Expo

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>
    )
  }
}

同时也支持复杂样式(like transform)和简写(如 margin)感谢 css-to-react-native

❗️注意: flex 的工作方式类似于 CSS 简写, 而不是 React Native 中的 flex 用法。设置 flex: 1 则会设置 flexShrink 为 1。

Imagine how you'd write the property in React Native, guess how you'd transfer it to CSS, and you're probably right:

const RotatedBox = styled.View`
  transform: rotate(90deg);
  text-shadow-offset: 10px 5px;
  font-variant: small-caps;
  margin: 5px 7px 2px;
`

与 web-version 不同, React Native 不支持 keyframescreateGlobalStyle 。使用媒体查询或是嵌套 CSS 也会报警。

NOTE v2 支持百分比。为了实现这一目标,需要为所有简写强制指定单位。如果要迁移到v2, a codemod is available

Simpler usage with the metro bundler

If you'd prefer to just import styled-components instead of styled-components/native, you can add a resolverMainFields configuration that includes "react-native". This used to be supported in metro by default (and currently does work in haul) but appears to have been removed at some point.