React学习笔记 之 styled.components(一)

(零)目录

  1. 动机:介绍了styled.components的“禅”,对了解这个工具很有用
  2. 下载:没得说
  3. 上手:介绍了styledComponetns的基本使用方式:怎样创建样式组件、传递props、通过props为组件做适配、怎样为任意(eg.第三方)组件添加样式、扩展样式、加入额外的props、如何使用动画,最后介绍了对React Native的支持。

(一)动机

    来自Max Stoiber的一次演讲,摘要如下:我们现在处于一个“组件化”的时代,组件——是一个非常棒的概念,它非常适合于构建用户界面。通过组件,我们只需要了解一些很小的片段就可以理解整个系统,而不是千万行的模板。而组件化也有它的最佳实践:

    1)组件要小而聚焦

    其中最重要的一点就是将组件实现的细节与整体隔离开,类似下面这样:

// 不要这样



// 我们只需要关心组件是什么,而不需要知道它是怎么实现的

    2)使用“容器组件”(区分“容器”和“组件”):

    简单的来说:容器负责“逻辑”,组件负责“展现

  • Container-How things Work
  • Components-How things Look
class SidebarContainer extends Comment {
    componentDidMount() {
        fetch('api.com/sidebar')
            .then(res => {
                this.setState({
                    items: res.items
                })
            });
    }
    render() {
        return (
            
                {this.state.items.map(item => (
                    {item}
                ))}
            
        )
    }
}
// 容器与组件分离
class Sidebar extends Comment {
    componentDidMount() {
        fetch('api.com/sidebar')
            .then(res => {
                this.setState({
                    items: res.items
                })
            });
    }
    render() {
        return (
            
{this.state.items.map(item => (
{item}
))}
) } }

      说完了组件,另一个方面就是给组件添加样式(Styling)了,怎么样更好的去给组件添加样式呢?以下是一种最佳实践

    1)使用全局唯一的Class

    “将button的class用在header上——仅仅因为它有恰当的background或者font-family什么的”会导致许多意料不到的问题(更普遍的情况是将一种样式既用于header,又用于button——也会导致同样的问题;或者更糟糕的,使用.button span这种选择器,会产生使代码更难维护——一旦在其他地方应用了button,所有其内的span都会被影响,不论你愿不愿意),一旦明确了这个class只用在某个组件,那么问题就很好定位了。

    2)将组件作为用于添加样式的结构:

“不用grid这个Class,而使用Grid组件、Column组件”,就像Michael Chen说的:“如果你使用React,你就拥有了一种比CSS类名更强大的样式添加结构——组件

    但是,仅仅是知道最佳实践也没有用,这里有一个最大的问题——实践——尤其是DDL(Deadline,最后期限)的压迫,这让你根本无法使用最佳实践。这就是Max和Glen(CSS Modules的创造者之一)为什么创造了styled.components。我们“移除了从样式到组件的映射”,为什么——如果你只对每个class名字使用一次,那么为什么要使用这个名字?因为从本质上来说,class名字就是一种从样式到其他东西的映射。那么如果你只映射一次,为什么要这个映射?

    注意,我们使用的是真正的CSS,就像所有CSS一样,你可以在其中使用选择器、媒体查询:

import styled from 'styled-components';

const ColorChanger = styled.section`
  background: papayawhip;
  > h2 {
    color: palevioletred;
  }
  @media (min-width: 875px) {
    background: mediumseagreen;
    > h2 {
      color: papayawhip;
    }
  }
`
    (其他内容多是关于用法的,故省略)

(二)下载

npm install --save styled-components

    如果你不使用模块打包工具或者包管理器,我们提供了一个托管在unpkg CDN上的全局(“UMD”)版本,在HTML文件的底部加入就行:

    

    或者使用bower下载:

bower install styled-components=https://unpkg.com/styled-components/dist/styled-components.min.js

    添加完之后,你就可以在访问到一个window.styled的全局变量。

(三)上手

    1)创建组件

    styled.components使用模板字面量去给组件添加样式。同时,因为它移除了组件和样式之间的映射,所以当你定义样式的时候,你实际上是创建了一个React组件,并将样式附给了它:

// Create a Title component that'll render an 

tag with some styles const Title = styled.h1` font-size: 1。5em; text-align: center; color: palevioletred; `; // Create a Wrapper component that'll render a
tag with some styles const Wrapper = styled.section` padding: 4em; background: papayawhip; `; // Use Title and Wrapper like any other React component – except they're styled! render( Hello World, this is my first styled component! );

    2)传递props

// Create an Input component that'll render an  tag with some styles
const Input = styled.input`
  padding: 0.5em;
  margin: 0.5em;
  color: palevioletred;
  background: papayawhip;
  border: none;
  border-radius: 3px;
`;

// Render a styled text input with a placeholder of "@mxstbr", and one with a value of "@geelen"
render(
  
);

    3)通过props做适配

你可以将一个函数传入styled组件的模板字符串中,从而通过props为组件做适配:

const Button = styled.button`
  /* Adapt the colours 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(
  
);

    4)为任意组件添加样式

    styled方法对所有你自己的、第三方的组件都工作的很好——这些组件都会将className这个prop传入渲染的子组件,styled方法的工作原理和他们一样。最终,为了使样式生效,这个className必须被传入真实的DOM节点。

// This could be react-router's Link for example
const Link = ({ className, children }) => (
  
    {children}
  
)

const StyledLink = styled(Link)`
  color: palevioletred;
  font-weight: bold;
`;

render(
  
Unstyled, boring Link
Styled, exciting Link
);

    当并不必要的时候,仔细考虑一下是否要将你自己的组件包裹在styled组件中——自将会关闭props的自动白名单(?),并且背离了将样式组件和容器组件分离的建议。

    你也可以将一个标签传入sytled(),就像styled('div'),实际上,styled.components这种语法只是styled()方法的别名而已。(styled-components总是通过class生成一个真实的样式表,这种样式名会通过className prop传入React组件中-包括第三方组件)。

    5)扩展样式

    经常情况下,你可能想要使用一个组件——但是需要对原来做出一些小小的改变。现在你可以将它传入一个插值函数中,通过props改变这个组件(覆盖这个样式需要费一番功夫?)。最简单的方法如下:

// The Button from the last section without the interpolations
const Button = styled.button`
  color: palevioletred;
  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;
`;

// We're extending Button with some extra styles
const TomatoButton = Button.extend`
  color: tomato;
  border-color: tomato;
`;

render(
  
Tomato Button
);

    注意:你只能在明确知道组件是一个“样式组件”的使用使用Comp.extend语法,如果你的组件来自于其他文件、或者第三方库,最好使用styled(Comp)——可以完成相同的功能,不过可以作用于所有React组件。在这里,你可以了解到关于Comp.extend和styled(Comp)区别的更多信息。

    在非常罕见的情况下,你想要改变styled.components渲染的是哪个标签或者是组件(比如想要对一个应用一个 Normal Link Tomato Link

);

    6)加入额外的props

    为了避免向一个渲染的组件、元素加入一些props可能发生的不必要嵌套,你可以使用.attr构造器——它允许你为组件附加额外的props。下面演示了这种方法:你可以向元素加入静态的props、加入第三方的prop(比如向React Router的Link组件中加入‘activeClassName’)、甚至加入更动态的props。.attrs对象也可以接受方法——方法接受组件的props,返回值同样也会被并入结果props中。

const Input = styled.input.attrs({
  // we can define static props
  type: 'password',

  // or we can define dynamic ones
  margin: props => props.size || '1em',
  padding: props => props.size || '1em'
})`
  color: palevioletred;
  font-size: 1em;
  border: 2px solid palevioletred;
  border-radius: 3px;

  /* here we use the dynamically computed props */
  margin: ${props => props.margin};
  padding: ${props => props.padding};
`;

render(
  

);

    7)动画

    @keyframes的CSS动画并不属于一个单一组件的范围,但是你又不想他们成为全局的,这就是我们为什么提供了一个keyframes助手——它会为keyframe自动生成一个独一无二的名字,你可以在整个APP范围中使用这个名字。在这种情况下,你获得了使用JavaScript的便捷性,并且避免了名称冲突!

// keyframes returns a unique name based on a hash of the contents of the keyframes
const rotate360 = 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: ${rotate360} 2s linear infinite;
  padding: 2rem 1rem;
  font-size: 1.2rem;
`;

render(
  < 

你可能感兴趣的:(React)