使用 styled-components 定義組件樣式

styled-components 是一個常用的 css in js 類庫付翁。和所有同類型的類庫一樣,通過 js賦能解決了原生 css所不具備的能力晃听,比如變量、循環(huán)砰识、函數(shù)等能扒。

動機

  • 自動關(guān)聯(lián)css
  • 可以在樣式定義中直接引用到 js 變量,共享變量
  • 自動生成獨立的類名辫狼,避免重復初斑、重疊或拼寫錯誤
  • 簡單的動態(tài)樣式,不用寫很多類名
  • 支持組件之間繼承膨处,方便代碼復用见秤,提升可維護性
  • 方便樣式維護,我們只需定位到某個組件真椿,就能快速改變其樣式

安裝

執(zhí)行以下命令便能快速安裝依賴:

npm install --save styled-components

或者

yarn add styled-components

基本用法

styled-components使用標簽模板來對組件進行樣式化鹃答。

它移除了組件和樣式之間的映射。這意味著突硝,當你定義你的樣式時测摔,你實際上只是創(chuàng)建了一個普通的 React 組件,你定義的樣式也附在它上面解恰。

下面我們將寫兩個簡單的組件來說明锋八,一個容器組件Wrapper,一個標題H1

Wrapper.js

import styled from "styled-components";

const Wrapper = styled.div`
  height: 200px;
  width: 400px;
  display: flex;
  justify-content: center;
  align-items: center;
  background: aqua;
`;

export default Wrapper;

H1.js

import styled from "styled-components";

const H1 = styled.h1`
  font-size: 32px;
  font-weight: bolder;
  color: chocolate;
`;

export default H1;

App.js

import React from "react";
import ReactDOM from "react-dom";
import Wrapper from "./Wrapper";
import H1 from "./H1";

function App() {
  return (
    <Wrapper>
      <H1>Hello,This is a demo of style components!</H1>
    </Wrapper>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

運行程序护盈,我們就能看到如下效果:

style-components-demo.png

此時挟纱,h1應用了我們定義的樣式。

基于Props做樣式判斷

模板標簽的函數(shù)插值能拿到樣式組件的 props腐宋,可以據(jù)此調(diào)整我們的樣式規(guī)則紊服。

第一種方式:

Button.js

import styled from "styled-components";

const Button = styled.button`
  min-width: 64px;
  background: ${props => (props.primary ? "blue" : "transparent")};
  color: ${props => (props.primary ? "white" : "palevioletred")};
  font-size: 14px;
  margin: 8px;
  padding: 8px;
  border: ${props => (props.primary ? "none" : `2px solid palevioletred`)};
  border-radius: 3px;
`;

export default Button;

上述示例中如果primary屬性存在,則按鈕背景色會變成藍色脏款,邊框消失围苫,并且文字顏色變成白色,使用方式及效果如下:

<div>
  <Button>Normal Button</Button>
  <Button primary>Primary Button</Button>
</div>

運行效果:

primary-button.png

此外撤师,我們還可以使用css定義一個樣式剂府,然后根據(jù)屬性判斷來調(diào)整我們的樣式規(guī)則,這就有了第二種方式:

Button.js

import styled, { css } from "styled-components";

const disabledStyle = css`
  background: transparent;
  color: rgba(0, 0, 0, 0.38);
  border: 2px solid rgba(0, 0, 0, 0.38);
`;

const Button = styled.button`
  min-width: 64px;
  background: ${props => (props.primary ? "blue" : "transparent")};
  color: ${props => (props.primary ? "white" : "palevioletred")};
  font-size: 14px;
  margin: 8px;
  padding: 8px;
  border: ${props => (props.primary ? "none" : `2px solid palevioletred`)};
  border-radius: 3px;
  ${props => props.disabled && disabledStyle};
`;

export default Button;

此時剃盾,如果我們給 Button 組件一個disabled屬性腺占,則disabledStyle中的樣式會自動覆蓋原有樣式中對應的部分淤袜。

<Button disabled>Disabled Button</Button>

運行效果:

disabled-button.png

最后,我們還可以直接傳入一個樣式屬性來控制組件樣式的規(guī)則衰伯,比如铡羡,我們希望能自定義按鈕的最小寬度,此時我們可以調(diào)整Button.js為:

import styled from "styled-components";

const Button = styled.button`
  min-width: ${props => props.minWidth || 64}px;
  background: ${props => (props.primary ? "blue" : "transparent")};
  color: ${props => (props.primary ? "white" : "palevioletred")};
  font-size: 14px;
  margin: 8px;
  padding: 8px;
  border: ${props => (props.primary ? "none" : `2px solid palevioletred`)};
  border-radius: 3px;
`;

export default Button;

此時意鲸,只要我們在使用 Button 組件時烦周,給minWidth屬性賦值,按鈕就會按照我們制定的最小寬度渲染怎顾。

<Button minWidth={24}>Mini Button</Button>
mini-button.png

擴展樣式

樣式擴展主要針對當前組件有部分樣式不滿足需求的情況读慎,此時我們可以通過樣式擴展來進行樣式調(diào)整,比如:我們希望上面例子中的 Button 組件的邊框顏色和字體顏色變成藍色槐雾,此時我們僅僅需要下面一小段代碼調(diào)整即能滿足需求:

const BlueButton = styled(Button)`
  color: blue;
  border: 2px solid blue;
`;
<BlueButton>Blue Button</BlueButton>
blue-button.png

在某些場景下夭委,我們可能不僅僅只是想要修改組件的樣式,甚至想要更新組件的渲染元素募强,styled-components曾經(jīng)提供了一種方式來滿足我們的需求株灸,即.withComponent()方法。不幸的是在后續(xù)版本中擎值,此方法將會被廢棄慌烧。但令我們欣慰的是:styled-components最新版本為我們提供了一種新的方式,就是as屬性幅恋。

假設杏死,我們想要使用<a>來渲染我們的 Button 組件,我們僅僅需要在使用 Button 時捆交,賦予一個as屬性即可:

<Button as="a" >
  Link Button
</Button>

運行效果:

link-button.png

同樣的淑翼,我們也可以使用我們自己定義的其它組件來給as屬性賦值。

自定義任意組件的樣式

styled-components實際上也是通過className的方式添加樣式品追,所以玄括,只要我們的組件有className,我們就能使用styled-components自定義其樣式。

import React from "react";
import styled from "styled-components";

const P = ({ className, children }) => <p className={className}>{children}</p>;

const CustomP = styled(P)`
  color: blue;
  font-size: 32px;
`;

export { P, CustomP };

App.js

<div>
  <P>這是一段普通的文本內(nèi)容</P>
  <CustomP>這是一段自定義樣式的文本內(nèi)容</CustomP>
</div>

運行效果:

custom-style.png

使用.attrs添加屬性

我們可以使用attrsAPI 來為樣式組件添加一些屬性肉瓦,它們也可以通過標簽模板插值函數(shù)拿到 props 傳值遭京。

import styled from "styled-components";

const PasswordInput = styled.input.attrs({
  type: "password",
  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 PasswordInput;

App.js

<PasswordInput placeholder="請輸入密碼" size="0.25rem" />

運行效果:

password-input.png

動畫

帶有@keyframesCSS animations,一般來說會產(chǎn)生復用泞莉。styled-components暴露了一個keyframesAPI哪雕,我們使用它產(chǎn)生一個可以復用的變量。這樣鲫趁,我們在書寫css樣式的時候使用 JavaScript 的功能斯嚎,為CSS附能,并且避免了名稱沖突。

import styled, { keyframes } from "styled-components";

const rotateStyle = keyframes`
    from {
    transform: rotate(0deg);
  }

    to {
    transform: rotate(360deg);
  }
`;

const Rotate = styled.div`
  display: inline-block;
  animation: ${rotateStyle} 2s linear infinite;
  padding: 2rem 1rem;
  font-size: 1.2rem;
`;

export default Rotate;

App.js

<Rotate>旋轉(zhuǎn)</Rotate>

運行效果:

rotate.gif

父組件中定義子組件樣式

styled-components提供了component selector組件選擇器模式來代替我們以往對 class 名的依賴堡僻。

開篇的示例糠惫,如果我們想要在 Wrapper 中改變H1的顏色為白色,可以有下面兩種方式:

第一種,通過h1查找钉疫,并修改樣式:

Wrapper.js

const Wrapper = styled.div`
  height: 200px;
  width: 400px;
  display: flex;
  justify-content: center;
  align-items: center;
  background: aqua;

  > h1 {
    color: white;
  }
`;

第二種硼讽,通過H1的組件名查找元素并修改樣式:

const Wrapper = styled.div`
  height: 200px;
  width: 400px;
  display: flex;
  justify-content: center;
  align-items: center;
  background: aqua;

  ${H1} {
    color: white;
  }
`;

App.js

<Wrapper>
  <H1>Hello,This is a demo of style components!</H1>
</Wrapper>

以上兩種方式運行效果如下:

css-in-parent.png

注意:下面這種方式不支持在父組件中定義自組件樣式

class A extends React.Component {
  render() {
    return <div />;
  }
}

const B = styled.div`
  ${A} {
  }
`;

因為 A 繼承ReactComponent,不是被 styled 構(gòu)造過的牲阁。我們的組件選擇器只支持在Styled Components創(chuàng)建的樣式組件固阁。

附注

有時候可能由于優(yōu)先級的問題,我們自定義的樣式無法使用咨油,此時我們只需要使用&&就能提升其優(yōu)先級:

const CustomButton = styled(Button)`
  && {
    width: 88px;
  }
`;

總結(jié)

這篇文章主要介紹了styled-components的基本用法您炉,包括通過屬性控制樣式規(guī)則、樣式擴展役电、自定義組件樣式、使用.attrs添加屬性棉胀、動畫等法瑟,希望可以通過閱讀此文章數(shù)量掌握如何使用styled-components定義組件樣式。

查看示例源碼

參考文章

styled-components 官網(wǎng)

Styled-Components

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唁奢,一起剝皮案震驚了整個濱河市霎挟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌麻掸,老刑警劉巖酥夭,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異脊奋,居然都是意外死亡熬北,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門诚隙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讶隐,“玉大人,你說我怎么就攤上這事久又∥籽樱” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵地消,是天一觀的道長炉峰。 經(jīng)常有香客問我,道長脉执,這世上最難降的妖魔是什么疼阔? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮适瓦,結(jié)果婚禮上竿开,老公的妹妹穿的比我還像新娘谱仪。我一直安慰自己,他們只是感情好否彩,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布疯攒。 她就那樣靜靜地躺著,像睡著了一般列荔。 火紅的嫁衣襯著肌膚如雪敬尺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天贴浙,我揣著相機與錄音砂吞,去河邊找鬼。 笑死崎溃,一個胖子當著我的面吹牛蜻直,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播袁串,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼概而,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了囱修?” 一聲冷哼從身側(cè)響起赎瑰,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎破镰,沒想到半個月后餐曼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡鲜漩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年源譬,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宇整。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡瓶佳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鳞青,到底是詐尸還是另有隱情霸饲,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布臂拓,位于F島的核電站厚脉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏胶惰。R本人自食惡果不足惜傻工,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧中捆,春花似錦鸯匹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蟋滴,卻和暖如春染厅,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背津函。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工肖粮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尔苦。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓涩馆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親允坚。 傳聞我的和親對象是個殘疾皇子凌净,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容