【CSS模組化之路3】 使用?styled-components來進行react開發

AlienZHOU發表於2018-06-15

CSS是一門幾十分鐘就能入門,但是卻需要很長的時間才能掌握好的語言。它有著它自身的一些複雜性與侷限性。其中非常重要的一點就是,本身不具備真正的模組化能力。

系列文章連結 ↓ ↓

1. 面臨的問題

CSS中雖然有@import功能。然而,我們都知道,這裡的@import僅僅是表示引入相應的CSS檔案,但其模組化核心問題並未解決——CSS檔案中的任何一個選擇器都會作用在整個文件範圍裡。

而如今的前端專案規模越來越大,已經不是過去隨便幾個css、js檔案就可以搞定的時代。與此同時的,對於一個大型的應用,前端開發團隊往往也不再是一兩個人。隨著專案與團隊規模的擴大,甚至是專案過程中人員的變動,如何更好進行程式碼開發的管理已經成為了一個重要問題。用CSS實現一些樣式往往並不是最困難的所在,難的是使用一套合理的CSS架構來支援團隊的合作與後續的維護。

What we want is to be able to write code that is as transparent and self-documenting as possible.

本系列文章會介紹一些業界在探索CSS模組化程式中提出的方案。在前兩篇文章中,我介紹了如果使用BEM與名稱空間來規範與架構你的CSS以及如何使用Webpack中的CSS modules。在這篇文章中,我會介紹styled-components這種CSS in JS方案,以及如何在React中使用。

2. styled-components是什麼

隨著React等前端技術的不斷流行,元件化的思想開始受到越來越多的人重視。以元件為中心的開發思路使得各種 css-in-js 實踐出現。

【CSS模組化之路3】 使用?styled-components來進行react開發
【CSS模組化之路3】 使用?styled-components來進行react開發

?styled-components,就是這些方案中的一種。它既具備了 css-in-js 的模組化與引數化的優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。這些優點都是它漸漸流行的原因。

如果你正在學習或使用React技術棧,就非常有必要了解一下?styled-components了。接下來的部分,就會帶著你迅速瞭解styled-components在React中的一些基本使用方式與使用場景。

P.S. 最新版 (v3.1.0) 的styled-components在SSR上有了極大的效能提升: you can now use streaming server-side rendering with styled-components — v3.1.0: A massive performance boost and streaming server-side rendering support

3. 在react中使用styled-components

3.1. 基本用法

那麼,如何在我們的react專案中使用styled-components呢?官網上有一句話非常形象:

It removes the mapping between components and styles. This means that when you’re defining your styles, you’re actually creating a normal React component, that has your styles attached to it.

簡單來說,就是在你使用styled-components進行樣式定義的同時,你也就建立了一個React元件。來先看一下它基本語法:

import styled from 'styled-components';
const ListWrap = styled.ul` margin: 0;
padding: 0;
`
;
const Item = styled.li` margin: 10px 0;
padding: 5px 15px;
border-left: 3px solid #333;
font-size: 16px;
list-style: none;
font-weight: bold;
`
;
複製程式碼

上面這段程式碼,其實就是定義了一個li元素的各種樣式資訊(邊距、邊框、字型等等)。是不是和直接在.css檔案中直接寫css很像?

注意,當我們將這個styledli元素賦給了Item這個變數時,我們也就建立了一個叫Item的React元件。因此,我們可以在JSX中直接使用Item

import React, {Component
} from 'react';
export default class List extends Component {
render() {
return ( <
ListWrap>
<
Item>
這是一條普通的記錄<
/Item>
<
Item>
這也是一條普通的記錄<
/Item>
<
/ListWrap>
)
}
}複製程式碼
【CSS模組化之路3】 使用?styled-components來進行react開發

是不是非常方便?

如果你對ES6熟悉的話,也許已經發現了,在使用styled設定css樣式的語法裡,用到了模板字串。因此,對於樣式,我們完全可以加入變數計算。更進一步的,我們可以通過獲取React元件的props來更改相應的css屬性:

const Item = styled.li`    margin: 10px 0;
padding: 5px 15px;
border-left: 3px solid #333;
font-size: 16px;
list-style: none;
font-weight: bold;
text-decoration: ${props =>
props.underline ? 'underline' : 'none'
}
;
`
;
export default class List extends Component {
render() {
return ( <
ListWrap>
<
Item>
這是一條普通的記錄<
/Item>
<
Item>
這也是一條普通的記錄<
/Item>
<
Item underline>
這條記錄有一條下劃線<
/Item>
<
/ListWrap>
)
}
}複製程式碼
【CSS模組化之路3】 使用?styled-components來進行react開發

這一語法也是styled-components工作的核心之一。原因在於,使用模板字串時,下面這兩行程式碼是等價的:

func`I love ${some_lib
}
&
styled-component`
func(['I love ', ' &
styled-component'
], some_lib)複製程式碼

如果想具體瞭解,可以看文末的參考連結。

3.2. 擴充套件已有樣式

有些時候,我們想要在已有的元件樣式基礎上,新增一些其他的樣式屬性,從而建立一個新的元件。

例如,對於上一節中的Item元件,我們想要在此基礎上,建立一個紅底白字的新Item樣式,但是其他屬性(字型、邊距等)保持一致。使用styled-components的styled方法可以很容易實現:

const RedItem = styled(Item)`    color: #fff;
background: #991302;
`
;
export default class List extends Component {
render() {
return ( <
ListWrap>
<
Item>
這是一條普通的記錄<
/Item>
<
Item>
這也是一條普通的記錄<
/Item>
<
Item underline>
這條記錄有一條下劃線<
/Item>
<
RedItem>
這是一條紅色的記錄<
/RedItem>
<
/ListWrap>
)
}
}複製程式碼
【CSS模組化之路3】 使用?styled-components來進行react開發

是不是非常簡單?這裡需要一提的是,對於styled.li這種書寫模式,實際上和styled('li')是等價的,只是一種方法的別名而已。

3.3. 樣式繼承

實際上,在styled-components中,對於元件的樣式繼承可以使用extend方法。因此,對於上一小節中的RedItem元件,我們也完全可以使用extend方法來實現:

const RedItem = Item.extend`    color: #fff;
background: #991302;
`
;
複製程式碼
【CSS模組化之路3】 使用?styled-components來進行react開發

在這個例子中,在css部分的程式碼是一樣的。那麼extendstyled兩者有什麼區別呢?官網上有一句話解釋的非常清楚:

The styled() factory generates new component styles with a new class. Calling extend creates new component styles by extending the old one, and thus doesn’t generate two classes for a single component. (styled() factory does that)

怎麼理解這句話呢?我們如果去審查頁面元素,就會發現區別:styled方法會建立一個新的類.iVuaxi來應用這兩行樣式,而Item本身的樣式依舊存在於.bWdYgn類中;而使用extend方法後則會在.fYpJfw類中實現所有的樣式,並不會建立兩個css類。

【CSS模組化之路3】 使用?styled-components來進行react開發

那麼,什麼時候使用extend方式,什麼時候使用styled方式呢?styled-components官方推薦儘量去使用extend方式。當該react元件不是一個styled-components元件時,使用styled方式。

3.4.修改標籤型別

除了需要繼承元件樣式外,有時候,我們可能想要更換該元件的HTML標籤。例如按鈕,我們已經有了一個button元件的樣式,想要再創造一個一樣的a標籤按鈕。這時候,我們就可以使用withComponent方法:

// 使用withComponent方法修改標籤型別const DivItem = Item.withComponent('div');
export default class List extends Component {
render() {
return ( <
ListWrap>
<
Item>
這是一條普通的記錄<
/Item>
<
Item>
這也是一條普通的記錄<
/Item>
<
Item underline>
這條記錄有一條下劃線<
/Item>
<
RedItem>
這是一條紅色的記錄<
/RedItem>
<
ExtendedItem>
這條記錄使用了‘extend’<
/ExtendedItem>
<
DivItem>
這實際上是個div <
/DivItem>
<
/ListWrap>
)
}
}複製程式碼
【CSS模組化之路3】 使用?styled-components來進行react開發

3.5. 新增動畫keyframes

當然,styled-components作為一個元件樣式方面的工具,肯定不會漏掉css3中的重要功能——動畫。我們完全可以在使用styled-components建立的元件中,設定相應的css3動畫。不過和之前稍有不同的是,我們還需要從styled-components庫中匯出一個keyframes方法。

下面,我們就來建立一個帶有動畫的Item。首先,使用keyframes方法建立css3動畫

import styled, {keyframes
} from 'styled-components';
const MyAnimation = keyframes` from {
padding-left: 0;
background: #991302;

} to {
padding-left: 50px;
background: #009317;

}`
;
複製程式碼

然後,使用繼承的方式,建立一個帶動畫的元件

const AnimateItem = RedItem.extend`    animation: ${MyAnimation
}
2s linear infinite alternate;
`
;
複製程式碼
【CSS模組化之路3】 使用?styled-components來進行react開發

3.6. 全域性樣式

有些時候,在開發中需要設定一些全域性的樣式,這個該怎麼處理呢?典型的,當我們想要為body元素設定一些屬性時,該怎麼辦呢?

別擔心,styled-components提供了injectGlobal方法來實現它。呼叫injectGlobal並不會返回一個元件,而是會將injectGlobal中的css相關樣式直接新增到<
style>
標籤內部。同樣的,需要匯出injectGlobal方法:

import styled, {keyframes, injectGlobal
} from 'styled-components';
injectGlobal` body {
border: 5px solid #991302;
background: #ddd;

}`
;
複製程式碼
【CSS模組化之路3】 使用?styled-components來進行react開發

如果我們去看頁面輸出的話,可以看到這一段樣式:

【CSS模組化之路3】 使用?styled-components來進行react開發

這就是我們設定全域性樣式後的輸出。

4. 使用styled-components的一些優點

使用styled-components來進行React技術棧的開發有許多優勢,這裡總結了一篇post裡的一些觀點:

  1. 壓縮你的樣式程式碼(Compressed Styles)。使用styled-components可以有效簡化部分樣式的編寫。
  2. 寫出更清爽的JSX程式碼(Clearer JSX)。
    原先的JSX
    使用styled-components後的JSX
  3. 實現樣式的組合與繼承(Composing Styles)
  4. 屬性過濾(Prop filtering)。styled-components會通過白名單的方式過濾無效的屬性。

5. 完善你的styled-components開發環境

5.1. vs code外掛

工欲善其事,必先利其器。如果你使用vs code進行開發,可以很方便地安裝styled-components外掛:vscode-styled-components。該外掛會進行語法與智慧提示,提高我們的開發效率。

使用vscode-styled-components外掛前
使用vscode-styled-components外掛後

5.2. stylelint

如果你在使用styled-components的同時,也使用了stylelint來進行css檢查,那麼你很可能會遇到一些問題。因為styled-components會導致程式碼不符合某些檢查規則。

為了解決這個問題,styled-components提供了一個叫stylelint-config-styled-components的包來調整stylelint中的某些規則檢查。你可以在你的.stylelintrc檔案中新增配置:"processors": ["stylelint-processor-styled-components"]。這樣你就可以繼續使用stylelint了。具體配置方式可以參考這裡

參考資料

想了解CSS模組化相關內容,可以看看

如果你對文中提到一些點感興趣,也可以在這裡進一步閱讀相關資料。

來源:https://juejin.im/post/5b2351946fb9a00e5a4b4d79

相關文章