Styled-Components初探

isNeilLin發表於2017-11-20

概覽

  • props調整元件樣式
  • attrs封裝元件屬性
  • extend或者styled(Component)實現元件樣式繼承
  • 使用innerRef代替ref
  • ThemeProvider helper實現主題功能
  • keyframes helper實現動畫介面
  • injectGlobal設定全域性樣式

基礎用法

import React, { Component } from 'react';
import styled from 'styled-components';

const Title = styled.h1`
    font-size: 18px;
    text-align: center;
    color: palevioletred;
`
const Wrapper = styled.div`
    padding: 24px;
`
export default class StyledComponents extends Component {
    render(){
        return (
            <Wrapper>
                <Title>This is my first styled-component!</Title>
          </Wrapper>
        )
    }
}複製程式碼

props調整元件樣式

import React, { Component } from 'react';
import styled from 'styled-components';

const Button = styled.button`
    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;
`

export default class StyledComponents extends Component {
    render(){
        return (
            <Wrapper>
                <Button>Normal</Button>
                <Button primary>Primary</Button>
          </Wrapper>
        )
    }
}複製程式碼

attrs封裝元件屬性

import React, { Component } from 'react';
import styled from 'styled-components';

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

    // 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;
    margin: ${props=>props.margin};
    padding: ${props=>props.padding};
`
export default class StyledComponents extends Component {
    render(){
        return (
            <Wrapper>
                <Password placeholder="A small text input" size="1em"/>
                <Password placeholder="A bigger text input" size="2em"/>
          </Wrapper>
        )
    }
}複製程式碼

extend或者styled(Component)實現元件樣式繼承

import React, { Component } from 'react';
import styled from 'styled-components';


const Button = styled.button`
    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;
`
// extending styles
// way 1
const TomatoButton = Button.extend`
    color: tomato;
    border-color: tomato;
`
// way 2  better way
const AnotherTomatoButton = styled(Button)`
color: tomato;
border-color: tomato;
`

export default class StyledComponents extends Component {
    render(){
        return (
            <Wrapper>
                <Button>Normal</Button>
                <TomatoButton>TomatoButton</TomatoButton>
                <AnotherTomatoButton>AnotherTomatoButton</AnotherTomatoButton>
          </Wrapper>
        )
    }
}複製程式碼

使用innerRef代替ref

import React, { Component } from 'react';
import styled from 'styled-components';

const InnerRefInput = styled.input`
    padding: 0.5em;
    margin: 0.5em;
    color: palevioletred;
    background: papayawhip;
    border: none;
    border-radius: 3px;
`

export default class StyledComponents extends Component {
    render(){
        return (
            <Wrapper>
               <InnerRefInput placeholder="hover here"
                innerRef={ x => { this.input = x } }
                onMouseEnter={ () => this.input.focus() }
            />
          </Wrapper>
        )
    }
}複製程式碼

ThemeProvider helper實現主題功能

import React, { Component } from 'react';
import styled, {ThemeProvider} from 'styled-components';

const ThemeButton = styled.button`
    font-size: 1em;
    margin: 1em;
    padding: 0.25em 1em;
    border-radius: 3px;    
    color: ${props=> props.theme.main};
    border: 2px solid ${props=> props.theme.main};
`
ThemeButton.defaultProps = {
    theme: {
        main: 'palevioletred'
    }
}

const theme = {
    main: 'mediumseagreen'
}


export default class StyledComponents extends Component {
    render(){
        return (
            <Wrapper>
                <ThemeButton>Normal</ThemeButton>
                <ThemeProvider theme={theme}>
                    <div>
                        <ThemeButton>Themed</ThemeButton>
                        <br/>
                    </div>
                </ThemeProvider>
          </Wrapper>
        )
    }
}複製程式碼

非styled-components元件使用theme(主題)

import { withTheme } from 'styled-components'

class MyComponent extends React.Component {
  render() {
    console.log('Current theme: ', this.props.theme);
    // ...
  }
}

export default withTheme(MyComponent)複製程式碼

keyframes helper實現動畫介面

import React, { Component } from 'react';
import styled, {keyframes} from 'styled-components';

const rotate360 = keyframes`
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
`

const Rotate = styled.div`
    padding: 2rem 1rem;
    font-size: 1.2rem;
    display: inline-block;
    animation: ${rotate360} 2s linear infinite;
`
export default class StyledComponents extends Component {
    render(){
        return (
            <Wrapper>
               <Rotate>???</Rotate>
          </Wrapper>
        )
    }
}複製程式碼

injectGlobal設定全域性樣式

import { injectGlobal } from 'styled-components';

injectGlobal`
  @font-face {
    font-family: 'Operator Mono';
    src: url('../fonts/Operator-Mono.ttf');
  }

  body {
    margin: 0;
  }
`;複製程式碼