styled-components 結合 React 框架使用,能讓其支持 CSS in JS 的寫法。好比:css
const Button = styled.button`
color: grey;
`;
複製代碼
以上是 SC
(styled-components 簡稱,下同)的一個簡單用法,它很方便的建立了一個 Button 組件,而後你就能夠在任何地方使用這個組件。git
<Button>Test</Button>
複製代碼
這一切是怎麼作到的呢?下面咱們一步步拆解。github
有人可能對 SC
的怪異語法規則有些費解,它怎麼作到直接在 styled 後面得到一個 dom 節點,而後又拼接上一個字符串呢?其實 styled.button 等同於 styled('button'),是一個柯里化後的函數,而函數後能夠接模板字符串(兩個反引號包起來部分``)是 ES6 的一個新語法特性,相關文檔,好比咱們能夠以下使用函數來接收一個字符串。bash
const fun = (args)=>{
console.log(args); // [ 'Hello' ]
}
fun`Hello`
複製代碼
而且其間也能夠加入表達式。app
const fun = (args, exp)=>{
console.log(args); // [ 'Hello ', ', Hi~' ]
console.log(exp); // World
}
const v = "World"
fun`Hello ${v}, Hi~`
複製代碼
能夠加入表達式的特性衍生出了 SC
的一種更高級用法,好比以上的 button,若是加入一個背景屬性,而此屬性會根據 props 而變化,則能夠寫成如下樣子。框架
const Button = styled.button`
color: grey;
background: ${props => props.background};
`;
複製代碼
剛剛有人可能好奇 styled.button 是怎麼就等同於 styled('button') 的,其實也簡單,SC
在倒入 styled 時把全部的 dom 節點柯里化後的函數都賦值給了 styled 的同名屬性,這樣就能使用上面的語法方式了,具體實現就是下面這段代碼。dom
domElements.forEach(domElement => {
styled[domElement] = styled(domElement);
});
複製代碼
那咱們在用 SC 的方式聲明瞭一個 Button 組件後,SC 作了哪些操做呢? 1,首先生成一個 componentId,SC 會確保這個 id 是惟一的,大體就是全局 count 遞增、hash、外加前綴的過程。hash 使用了 MurmurHash,hash 事後的值會被轉成字符串。生成的 id 相似 sc-bdVaJa
ide
componentId = getAlphabeticChar(hash(count))
複製代碼
2,在 head 中插入一個 style 節點,並返回 className;建立一個 style 的節點,而後塞入到 head 標籤中,生成一個 className,而且把模板字符串中的 style 結合 className 塞入到這個 style 節點中。其中 insertRule 方法函數
evaluatedStyles 是得到到的 style 屬性
const style = document.createElement("style");
// WebKit hack
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
const className = hash(componentId + evaluatedStyles);
style.sheet.insertRule('.className { evaluatedStyles }', 0)
複製代碼
3,根據解析的 props 和 className 來建立這個 element。性能
const newElement = React.createElement(
type,
[props],
[...children]
)
newElement.className = "第二部生成的節點"
複製代碼
SC
總體原理仍是比較簡單的,因爲直接用了 ES6 的的字符模板特性,對 style 和 props 部分的解析也比較快,因爲須要在運行過程當中不斷動態建立 Element 而且建立 style 消耗了部分性能。使用過程當中也有些要注意的地方,拿最初的 button 舉例,若是每次點擊那個 Button 都會改變一次 background,你會發如今點 200 次後,SC
會報一個 warning。
Over 200 classes were generated for component styled.button.
Consider using the attrs method, together with a style object for frequently changed styles.
Example:
const Component = styled.div.attrs({
style: ({ background }) => ({
background,
}),
})`width: 100%;`
<Component />
複製代碼
warning 表示建立了超過 200 個類,這是因爲每次 background 變化都會生成新的 Element 致使的,此時咱們按照提示能夠優化成直接使用節點的 style 屬性來修改樣式,避免重複生成節點類。
styled.button.attrs({
style: props => ({background: props.background})
})``
複製代碼
css in js 的寫法有不少優點,此處就很少說了,影響你們使用的很重要一點是性能,SC
團隊也一直對外宣稱要不斷改進性能,20年的 V5 版本作了不少提高,固然因爲實現機制,因此再怎麼優化也不可能達到原生寫法的性能。若是有對性能要求很嚴的網站建議不要使用,若是想寫的快寫的爽,用 SC
仍是很不錯的選擇。 號稱是 Beast Mode 的 V5 版本更新宣傳