react基础(十六)— styled-components

3,025 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

前言

大家好呀,我是L同学。上篇文章中react基础(十五)— css,我们学习了react中的css,包括内联样式、普通的css、css modules和CSS-in-JS。今天,我们详细介绍下CSS-in-JS中流行的styled-components。

styled-components的基本使用

首先我们写一个基本的Home组件。

import React, { PureComponent } from 'react'
export default class Home extends PureComponent {
  render() {
    return (
      <div className='home'>
        <h2>我是Home的标题</h2>
        <div className='banner'>
          <span>轮播图1</span>
          <span className='active'>轮播图2</span>
          <span>轮播图3</span>
          <span>轮播图4</span>
        </div>
      </div>
    )
  }
}

页面是长这样子的。

image.png 我们要使用styled-components,首先需要通过yarn add styled-components进行安装。

然后引入styled-components。

import styled from 'styled-components'

为了让我们写css代码有智能提示,我们先安装一个插件vscode-styled-components

image.png 我们需要安装第二个插件,第一个插件由于版本问题没有智能提示。

image.png

styled-components的本质是通过函数调用最终创建出一个组件。styled.div是一个函数,可以进行调用。在上篇文章中,我们讲过标签模板字符串可以通过模板字符串的方式对一个函数进行调用。最终返回一个组件。此时HomeWrapper是一个div,并且带有样式。如果我们写styled.span那么会生成一个span元素。

const HomeWrapper = styled.div`
  font-size: 20px;
  color: red;
`

然后我们把之前写得div标签替换成HomeWrapper。

export default class Home extends PureComponent {
  render() {
    return (
      <HomeWrapper>
        <h2>我是Home的标题</h2>
        <div className='banner'>
          <span>轮播图1</span>
          <span className='active'>轮播图2</span>
          <span>轮播图3</span>
          <span>轮播图4</span>
        </div>
      </HomeWrapper>
    )
  }
}

我们可以看到这个组件被自动添加上了一个不重复的class。styled-components会给该class添加了相关样式。它的子元素样式继承了父元素的样式。

image.png 我们想给h2元素添加单独的样式。此时可以通过styled.h2创建TitleWrapper组件。

const TitleWrapper = styled.h2`
  text-decoration: underline;
`

把h2元素替换成TitleWrapper。

<TitleWrapper>我是Home的标题</TitleWrapper>

此时,h2元素添加上了下划线。

image.png 此外,styled-components还支持类似于less、scss等css预处理器一样的样式嵌套:

  • 支持直接子代选择器或后代选择器,并且直接编写样式;
  • 可以通过&符号获取当前元素;
  • 直接伪类选择器、伪元素等

接下来我们测试下。

const HomeWrapper = styled.div`
  font-size: 20px;
  color: red;
  .banner {
   background-color: blue;
  }
  span {
    color: #fff;
    &.active {
      color: red;
    }
    &:hover {
      color: green;
    }
    &::after {
      content: 'aaa';
    }
  }
`

我们可以看到样式可以正常生效。 image.png

props、attrs属性

styled-components还可以props穿透,把属性穿透到元素中。

一般情况下我们这样写一个密码输入框。

<input type="password" />

那么通过styled-components生成的input组件可以是一个密码输入框吗?

首先生成一个input组件。

const MyInput = styled.input`
  background-color: lightpink;
`

生成的MyInput组件添加type=password

<MyInput type='password'/>

此时输入框背景颜色变为了粉色,同时是个密码输入框,这是因为添加的属性穿透到了input元素中。

image.png 此外,还可以添加attrs属性。attrs十个函数,可以进行调用,返回值也是一个函数,后面可以继续调用。

const MyInput = styled.input.attrs({
  placeholder: '请输入密码',
  bColor: 'red'
})`
  background-color: lightpink;
  border-color: ${props => props.bColor};
`

image.png

props还可以被传递到styled组件。获取props需要通过${}传入一个插值函数,props会作为该函数的参数。这种方式可以有效解决动态样式的问题。

如果我想要获取state中的样式呢?

    this.state = {
      color: 'purple'
    }
<MyInput type='password' color1={this.state.color}/>

我们在组件中写得属性color1={this.state.color}和attrs函数中写得属性{ placeholder: '请输入密码', bColor: 'red' }会结合起来传递到props中。

const MyInput = styled.input.attrs({
  placeholder: '请输入密码',
  bColor: 'red'
})`
  background-color: lightpink;
  border-color: ${props => props.bColor};
  color: ${props => props.color1};
`

我们可以看到样式可以正常显示。

image.png 之前我们写了很多样式,跟jsx代码放在一起,现在我们把样式单独放在一个文件中style.js。

styled高级特性

支持样式继承

我们通过styled-components生成两个按钮组件,一个是普通按钮,另一个是主要按钮,主要按钮跟普通按钮的一些样式一样。

import React, { PureComponent } from 'react'
import Home from '../home'
import Profile from '../profile'

import styled from 'styled-components'

const MyButton = styled.button`
  padding: 10px 20px;
  border-color: red;
  color: red;
`

const MyPrimaryButton = styled.button`
  padding: 10px 20px;
  border-color: red;
  color: #fff;
  background-color: green;
`
export default class App extends PureComponent {
  render() {
    return (
      <div id='app'>
        App
        <Home />
        <Profile />
        <MyButton>我是普通按钮</MyButton>
        <MyPrimaryButton>我是主要按钮</MyPrimaryButton>
      </div>
    )
  }
}

我们可以看到两个按钮正常显示。 image.png 主要按钮跟普通按钮的一些样式重复了,我们可以通过styled的样式继承来简化一些代码。

const MyPrimaryButton = styled(MyButton)`
  color: #fff;
  background-color: green;
`

两个按钮正常显示。

image.png

设置主题

styled支持设置主题,来达到共享样式的目的。

首先引入ThemeProvider。

import styled, {ThemeProvider} from 'styled-components'
  render() {
    return (
      <ThemeProvider theme={{themeColor: 'green', fontSize: '30px'}}>
        App
        <Home />
        <hr />
        <Profile />
        <MyButton>我是普通按钮</MyButton>
        <MyPrimaryButton>我是主要按钮</MyPrimaryButton>
      </ThemeProvider>
    )
  }

对Home组件的h2元素设置主题。

export const TitleWrapper = styled.h2`
  text-decoration: underline;
  color: ${props => props.theme.themeColor};
  font-size: ${props => props.theme.fontSize};
`

我们可以看到Home组件的颜色和大小都设置成了theme指定的样式。

image.png