styled-components:前端元件拆分新思路

神三元發表於2019-07-02

一直在思考React元件如何拆分的問題,直到接觸到styled-components,讓我有一種如魚得水的感覺,今天我就給大家分享一下這個庫如何讓我們的前端元件開發的更優雅,如何保持更合適的元件拆分粒度從而更容易維護。

一、使用方法

styled-components是給React量身定製的一個庫,奉行React中all in js的設計理念,並將這個理念進一步發揮到極致,讓CSS也能夠成為一個個的JS模組。

使用起來也相當方便,首先安裝這個庫

npm install styled-components --save
複製程式碼

然後在style.js中使用(注意這裡不是style.css,樣式檔案全部是JS檔案)

import styled from 'styled-components';
//styled.xxx表示建立xxx這個h5標籤,
//後面緊接的字串裡面寫的是CSS程式碼
export const HeaderWrapper = styled.div`
  z-index: 1;
  position: relative;
  height: 56px;
  border-bottom: 1px solid #f0f0f0;
`;
複製程式碼

之後再React中使用它:

import React, {Component} from 'react';
import { HeaderWrapper } from './style.js';

class App extend Component{
    render() {
        return (
            <HeaderWrapper></HeaderWrapper>
        )
    }
}
export default App;
複製程式碼

Ok!這就是它的日常使用方式。如果有興趣可以去github的相應倉庫開啟更多使用姿勢:)

二、使用styled-component解決了哪些痛點

可能你還會有疑惑:這麼做有什麼好處呢?

1.CSS模組化

儘量降低模組之間的耦合度,利於專案的進一步維護。比起用原生的CSS,這是它首當其衝的優勢。

2.支援前處理器巢狀語法

如:

export const SearchWrapper = styled.div`
  position: relative;
  float: left;
  .zoom {
    right: 5px;
    &.focused {
      background: #777;
      color: #fff;
    }
  }
`;
複製程式碼

可以採用sass,less的巢狀語法,開發更加流暢。

3.讓CSS程式碼能夠處理邏輯

不僅僅是因為裡面的模板字串可以寫JS表示式,更重要的是能夠拿到元件的上下文資訊(state、props)

比如,在React元件中的JSX程式碼中寫了這樣一段:

<RecommendItem imgUrl={'xxx'}/>
複製程式碼

在相應的style.js中就能夠接受相應的引數:

export const RecommendItem = styled.div`
  width: 280px;
  height: 50px;
  background: url(${(props) => props.imgUrl});
  background-size: contain;
`;
複製程式碼

CSS能夠拿到props中的內容,進行相應的渲染,是不是非常酷炫?

4.語義化

如果以上幾點還不能體現它的優勢,那這一點就是對於前端開發者的毒藥。

現在很多人對標籤語義化的概念趨之若鶩,但其實大多數開發者都還是div+class一把擼的模式。難道是因為語義化不好嗎?能夠讓標籤更容易理解當然是件好事情,但是對於html5規範推出的標籤來說,一方面對於開發者來說略顯繁瑣,還是div、span、h1之類更加簡潔和親切,另一方面標準畢竟是標準,它並不能代表業務,因此並不具有足夠的表達力來描述紛繁的業務,甚至這種語義化有時候是可有可無的。我覺得這兩點是開發者更喜歡div+class一把擼的根本原因。

那好,照著這個思路,拿React元件開發而言,如果要想獲得更好的表達力,儘可能的語義化,那怎麼辦?可能你會暗笑:這還用說,拆元件啊!但元件真的是拆的越細越好嗎?

有人曾經說過:當你元件拆的越來越細的時候,你會發現每一個元件就是一個標籤。但是這會造成一些更加嚴重的問題。假設我們拆的都是UI元件,當我們為了語義化連一個button都要封裝成一個元件的時候,程式碼會臃腫不堪,因為會出現數量過於龐大的元件,非常不利於維護。

那,有沒有一個折中的方案呢?既能提高標籤語義化,又能控制JS檔案的數量。 沒錯,這個方案就是styled-components。

以首頁的導航為例, 取出邏輯後JSX是這樣:

<HeaderWrapper>
    <Logo/>
    <Nav>
        <NavItem className='left active'>首頁</NavItem>
        <NavItem className='left'>下載App</NavItem>
        <NavItem className='right'>
            <i className="iconfont">&#xe636;</i>
    	</NavItem>
        <SearchWrapper>
            <NavSearch></NavSearch>
            <i className='iconfont'>&#xe614;</i>
        </SearchWrapper>
    </Nav>
    <Addition>
        <Button className='writting'>
    	  <i className="iconfont">&#xe615;</i>
    	  來參加
    	</Button>
    	<Button className='reg'>註冊</Button>
    </Addition>
</HeaderWrapper>
複製程式碼
//style.js
import styled from 'styled-components';

export const HeaderWrapper = styled.div`
    z-index: 1;
    position: relative;
    height: 56px;
    border-bottom: 1px solid #f0f0f0;
`;

export const Logo = styled.div`
    position: absolute;
    top: 0;
    left: 0;
    display: block;
    width: 100px;
    height: 56px;
    background: url(${logoPic});
    background-size: contain;
`;

export const Nav = styled.div`
    width: 960px;
    height: 100%;
    padding-right: 70px;
    box-sizing: border-box;
    margin: 0 auto;
`;
//......
複製程式碼

拆分後的標籤基本是在style.js裡面匯出的變數名,完全自定義,這個時候CSS都成為了一個個JS模組,每一個模組相當於一個標籤(如:styled.div已經幫我們建立好了標籤),在模組下面完全可以再寫h5標籤。這樣的開發方式其實是非常靈活的。

三、開發過程中遇到的坑以及目前缺點

坑: 以前的injectGlobal已經被棄用,因此對於全域性的樣式檔案需要使用createGlobalStyle來進行引入。

//iconfont.js
//全域性樣式同理
import {createGlobalStyle} from 'styled-components'

export const IconStyle = createGlobalStyle`
@font-face {
  font-family: "iconfont";
  src: url('./iconfont.eot?t=1561883078042'); /* IE9 */
  src: url('./iconfont.eot?t=1561883078042#iefix') format('embedded-opentype'), /* IE6-IE8 
  //...
}

.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
`
複製程式碼

然後在全域性的根元件App.js裡面:

import { IconStyle } from './statics/iconfont/iconfont'
import { GlobalStyle } from  './style'
//import ...

function App() {
  return (
    <Provider store={store}>
      <div>
        {/* 通過標籤形式引入這些樣式 */}
        <GlobalStyle></GlobalStyle>
        <IconStyle></IconStyle>
        <Header />
        <BrowserRouter>
        <div>
          <Route path='/' exact component={Home}></Route>
          <Route path='/detail' exact component={Detail}></Route>
        </div>
        </BrowserRouter>
      </div>
    </Provider>
  );
}

export default App;
複製程式碼

對於styled-components缺點而言,我認為目前唯一的不足在於模板字串裡面沒有CSS語法,寫起來沒有自動提示,對於用慣IDE提示的人來說還是有美中不足的。不過也並不是什麼太大的問題,如果有相應的外掛或工具歡迎在評論區分享。

對於styled-components以及元件化一點小小的思考,記錄一下,希望能對各位有啟發。

相關文章