寫在前面的廢話
回到2013年,React憑空出世。但是在那時,我們會想,oh shit! 我們好不容易分離了HTML/CSS/JS, 為什麼出現了JSX,我們又需要把HTML和JS耦合在一起?React 創造了 HTML in JS. 在React中,我們知道,一切即元件。那既然HTML能在js裡寫,為什麼我們不把CSS也一起寫呢?這樣不才是一個真正的元件嗎?
Styled-components就是為React而生的,它是CSS in JS的下一代解決方案。以往我們想要做到css scope都需要在webpack中各種配置,或者使用js的解決方案。而styled-components你只需要import styled from `styled-components`;
即可。
甚至React完美的結合,不僅是從TagName上,還有Props上。使我們的程式碼有更好的語義化,可維護性更強,效率更高。當然我們無需考慮它的學習成本,只要你用過CSS或者SASS都可以立刻上手,因為它本身就是一種超集的存在。
接下來,我會逐步的介紹一些這段時間以來,我非常喜歡的獨有的特性。
開胃菜
const Button = styled.button`
background: #abcdef;
border-radius: 3px;
border: none;
color: white;
`;
console.log(Button); //styled component
console.log(new Button()); // react component
export default CustomButton extends React.component {
render() {
return <Button {...props} />
}
}
複製程式碼
styled-components 用了tagged template語法,直接為我們編寫樣式建立元件。
繼承
styled-components繼承樣式有兩種寫法如下
const Button = styled.button`
background: #abcdef;
border-radius: 3px;
border: none;
color: white;
`;
const OtherButton1 = styled(button)``;
const OtherButton2 = button.extend``; // 老的寫法,不推薦,未來會被廢棄
複製程式碼
寫法一的繼承,僅僅只會建立不一樣的css rule,而第二種寫法會複製一遍base component的css rule,然後在新增不一樣的進行css 權重覆蓋。不推薦
當然,還有一種有趣的“繼承” withComponent
,我們可以利用withComponent改變渲染的標籤
const Li = styled.li`
color:#abcdef;
`;
const A = Li.withComponent(`a`); // 將會渲染a標籤
複製程式碼
編譯後他們會使用不同的className,這對我們想用同個樣式,但是不同標籤非常有用。
樣式覆蓋
這裡所說的樣式覆蓋,主要是一些互動上的行為(hover, active)覆蓋。其實元件繼承也算是覆蓋的一種。
以往我們的覆蓋寫法如下:
const ListItem = styled.li`
padding: 0;
height: 48px;
&.left-item-focus {
.left-link {
background: ${props => props.color};
}
}
&:hover {
.left-icon {
color: #9e9e9e; // 500
}
}
`;
複製程式碼
而在styled中,我們可以使用styled-components 元件方式對我們的DOM進行引用,從而覆蓋樣式,如下
const Icon = styled.span`
color: red;
`;
const ListItem = styled.li`
&:hover ${Icon} {
color: green;
}
`;
複製程式碼
這依舊是我們過去的思路來覆蓋樣式,只是我們把選擇器直接使用styled
元件引用罷了。擁有這樣的介面,就更加讓我們無需去思考需要給元件取什麼className或者id,從而達到覆蓋樣式的做法。然而還有我最喜歡的另外一種寫法。
TIPS:元件的引用必須是styled-components包裝後的元件,直接是react的會報錯
const ListItem = styled.li``;
const Icon = styled.span`
color: red;
${ListItem}:hover & { // & 代表icon元件
color: green;
}
`;
複製程式碼
這段程式碼實現的是一樣的功能,只是我們思路轉換了一下。可以發現這樣的程式碼更加沒有侵入性。更加符合開放封閉原則,當我們不需要這個Icon元件時,直接把這個Icon刪除即可,我們不用去父元件裡尋找與該元件有關的樣式,不容易造成樣式汙染。突然覺得眼前一亮,有木有!
當然這種“子元件引用父級”的功能,還有更加廣泛的引用。你可以選擇該DOM任何parent,再對自己進行樣式的覆蓋。如下:
const Icon = styled.span`
color: red;
html.ie-8 & {
// fuck ie8
color: blue;
}
body.xxx & {
color: green;
}
`;
複製程式碼
當任何父級帶有class都會覆蓋Icon的樣式。這種“子元件引用父級”的功能也是我最喜歡的功能沒有之一。
在上面可以看見我們大量使用了&
作為選擇器,而&
還有另外的技巧。
const Example = styled.li`
color: red;
& {
color:blue;
}
&& {
color: green;
}
`;
複製程式碼
大家可以猜猜,這最終會渲染成什麼?
<li class=`sc-gzVnrw fmpfVE`></li>
複製程式碼
最終會編譯成如下class,但是我們的一個&
就代表一個class
權重也就是說我們最後會渲染原諒色,原因是li被作用於了.fmpfVE.fmpfVE
樣式表。這個功能非常有用,比如在你使用第三方元件想要覆蓋它的樣式的時候,我們就可以加多個&
來提高樣式權重,從而覆蓋第三方元件的樣式
Theme
關於Theme只想說一點,那就是結合第三方元件應該如何傳入Theme呢?我們有一個簡單的技巧。比如使用了Material-UI,如果我們需要基於它擴充我們自己的元件,並且需要樣式。
const ThemeProvider: React.SFC<ThemeProviderProps> = ({ themeName, children }) => {
const theme = themes[themeName];
return (
<StyledThemeProvider theme={theme}>
<MuiThemeProvider theme={theme}>
{React.Children.only(children)}
</MuiThemeProvider>
</StyledThemeProvider>
);
};
複製程式碼
之後只需要把我們需要呼叫的元件使用styled-components提供的withTheme
包裝一下我們的元件來獲取我們的theme。
這樣既可以在我們的styled-components裡取到theme,material裡也可以了。
以上就是我們所有的技巧了, 看了這麼多有意思的黑科技,難道你還不愛上styled-components嗎?
個人網站 www.meckodo
Github: github.com/MeCKodo