Styled Components:讓樣式也成為組件">Styled Components:讓樣式也成為組件

分類:IT技術 時間:2017-05-17

前言

為了應對越來越復雜的web應用,組件化應運而生,React、Vue等組件化框架使我們的程序更簡單更加可維護。然而,即使有了組件化前端開發者還是需要使用CSS編寫樣式,CSS很簡單,但CSS是相當有限的,沒有變量、循環和函數等邏輯讓CSS用起來十分混亂。LESS和SASS等語言的特性使樣式編寫有所好轉,但還是阻止不了CSS的混亂狀態。

最近,為了解決CSS混亂問題,人們開始考慮使用JS上編寫CSS, styled components 就是其中一種解決方案。styled components是一個React第三方庫,作用是可以將樣式寫成組件的形式,實現在JS上編寫CSS。

基本用法

安裝

npm install -S styled-components
 

使用styled-components不需要再使用className屬性來控制樣式,而是將樣式寫成更具語義化的組件的形式,如下例:

import React from 'react';
import styled from 'styled-components';
import { render } from 'react-dom';
 
const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: palevioletred;
`;
 
class App extends React.Component {
    render() {
        return (
            <Title>Hello world</Title>
        )
    }
}
 
render(
    <App />,
    document.getElementById('app')
);
 

結果:

上例中的styled.h1是一個標簽模板函數,緊跟其後的是一個模板字符串參數,“標簽模板”和“模板字符串”都是es6的語法,具體可以參考阮一峰老師ECMASCRIPT6入門中的 模板字符串 和 標簽模板

styled.h1函數返回一個React Component,styled components會為這個React Component添加一個class,該class的值為一個隨機字符串。傳給styled.h1的模板字符串參數的值實際上是CSS語法,這些CSS會附加到該React Component的class中,從而為React Component添加樣式:

更簡單地控制樣式 —— props參數

在React中是通過控制className和style來控制樣式的,如下例,Title組件需要判斷是否有primary屬性來判斷是否渲染”title-primary”類的樣式:

class Title extends React.Component {
    render() {
        const className = `title${this.props.primary ? ' title-primary' : ''}`;
        return (
            <div className={className}>{this.props.children}</div>
        );
    }
}
 
<Title primary>Hello world</Title>
 

styled components使用props來控制樣式,將控制樣式代碼放在樣式組件中,使React組件更加簡潔:

const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: ${props => props.primary ? 'SteelBlue' : 'palevioletred'};
`;
 
<Title primary>Hello world</Title>
 

上面兩種寫法非常相似,實際上還是要用CSS的語法編寫樣式。但是第一種寫法需要className或style作為“中間人”使JS找到對應的樣式,而styled components的寫法中樣式組件暴露props讓外層JS來控制樣式,不再需要className或style這樣的“中間人”, 移除了樣式和組件間的映射關系

支持全部CSS特性

實際上styled components使用的還是CSS,因此完美 支持CSS的所有特性 。偽類,媒體查詢,keyframes都可以在styled components中實現:

const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: palevioletred;
 
    &:hover {
        background-color: #ddd;
    }
 
    @media (max-width: 650px) {
        font-size: 1em;
    }
 
`;
 

上例中,鼠標放在“Hello world”的時候會變成灰色,窗口寬度少於650px的時候文字大小會變成1em。

CSS作用域

CSS有一個痛點——CSS的作用域是全局的。當兩個CSS選擇器有沖突時,會根據選擇器的權值確定使用哪一個選擇選擇器。當項目較大時,編寫的css選擇器很難判斷會不會把另外一個選擇器沖掉。

解決CSS作用域的其中一個方法就是使用 後代選擇器 ,這種用法和命名空間相似,即在每個選擇器前添加一個父元素的選擇器,從而減少選擇器沖突的概率:

#myParent .title {
    /*...*/
}
 
#myParent .title-primary {
    /*...*/
}
 

LESS和SASS的持選擇器嵌套的語法,該語法最終會編譯成後代選擇器的形式,和上述方法實際上是一樣的:

#myParent {
    .title {
        /*...*/
    }
 
    .title-primary {
        /*...*/
    }
}
 

使用嵌套語法能較好的解決CSS全局作用域的問題,但是,由於編譯出來的CSS選擇器過於具體,一個組件組件難以復用另一個組件的當時,你的組件樣式變得孤立起來。

上文有提到,使用styled components會給生成的React組件添加一個值為隨機字符串的className。使用同一個styled components生成的多個React組件的className是不同的,這種隨機className的機制使得 組件之間的className值不會沖突 ,從而解決了CSS全局作用域的問題。

styled components也支持css的嵌套語法:

const Title = styled.h1`
    font-size: 1.5em;
    text-align: center;
    color: palevioletred;
`;
 
const Wrapper = styled.div`
    font-size: 1.2em;
 
    .content1 {
        color: red;
    }
 
    .content2 {
        color: green;
    }
`;
 
<Wrapper>
    <div>You'd better don't do that like so:</div>
    <div className="content1">I am red</div>
    <div className="content2">I am green</div>
</Wrapper>
 

不推薦在styled components中使用嵌套,因為樣式組件的子組件的className不會被編譯成隨機值,這些子組件的類還是會受CSS的全局作用域影響。

分離邏輯組件和展示組件

使用styled components,可將組件分為邏輯組件和展示組件 ,邏輯組件只關註邏輯相關的部分,展示組件只關註樣式 。通過解耦成兩種組件,可以使代碼變得更加清晰可維護。

當邏輯有變化,如後臺拉取的數據的格式有所變化時,只需關註並修改邏輯組件上的代碼,展示組件的代碼不用動。而當UI需要變化時,只需改變展示組件上的代碼,並保證展示組件暴露的props接口不變即可。邏輯組件和展示組件各司其職,修改代碼時錯誤發生率也會有所減少。

CSS Module vs Styled Components

CSS Module是另一種解決全局作用域的方案,還沒了解CSS Module的朋友可以參考 CSS Modules 入門及 React 中實踐 和 CSS Modules 用法教程 這兩篇博文。

CSS Module只需修改構建代碼和使用模塊依賴引入className的方式即可使用,且支持less和sass的語法,樣式代碼不用修改即可讓使用CSS語法的舊項目零成本接入。而styled components是一種全新的樣式組件化的編程方式,不支持less和sass語法。

CSS Module還是JS和CSS分離的寫法,而styled components實際上是在JS上寫CSS。習慣JS、CSS和HTML都分離的人或許不習慣styled components的寫法。

最後

styled components一種全新的控制樣式的編程方式,它能解決CSS全局作用域的問題,而且移除了樣式和組件間的映射關系。傳統的web開發推崇HTML、CSS、Javascript都分離,styled components則有點“離經叛道”的味道——在JS上編寫CSS,什麽東西都在JS裏寫感覺是近幾年前端開發的趨勢,React就是一個活生生的例子。究竟這是不是一個好趨勢,現在還不好判斷,但是實踐和時間總會給我們一個答案。


Tags:

文章來源:


ads
ads

相關文章
ads

相關文章

ad