介紹:
styled-components 樣式化組件,主要作用是它可以編寫實際的CSS代碼來設計組件樣式,也不需要組件和樣式之間的映射,即創建后就是一個正常的React 組件,並且可以附加樣式給當前組件。下面通過兩種平台的樣式書寫來比較說明:
a.react-native 下寫樣式的方式:
var styles = StyleSheet.create({ container: { borderRadius: 4, borderWidth: 0.5, borderColor: '#d6d7da', }, title: { fontSize: 19, fontWeight: 'bold', }, activeTitle: { color: 'red', }, }); <View style={styles.container}> <Text style={[styles.title, this.props.isActive && styles.activeTitle]} /> </View>
通過 StyleSheet 庫創建一個樣式表,再到元素標簽上引用創建的樣式 styles.container
b.Html + Css的寫法:
<style type="text/css"> .container{ borderRadius: '5px', borderWidth: '5px', borderColor: '#d6d7da', } .title{ fontSize: '19px', fontWeight: 'bold', } .activeTitle{ color: 'red', } </style> <div class="container"><span class="title"></span></div>
根據上面兩種例子可以看出當元素需要某類樣式時,都需要與之對應,才能有具體的顯示效果。
接下來看 styled-components 樣式化組件是如何做到組件與樣式之間不需要映射的
如:創建一個 <h1>標簽 的樣式化組件,在React中直接使用創建好的Title組件就可以了
//在h1后添加附加的樣式
const Title = styled.h1` font-size: 1.5em; text-align: center; color: palevioletred; `;
render( <Title> Hello styled-component </Title> );
那么問題來了,通過styled-component創建的樣式化組件在頁面上最終渲染成什么呢了?
先看效果:
再看頁面代碼:實際上就是通過 <h1>元素標簽渲染的
幾種常用的樣式化組件方法
# injectGlobal # 編寫全局CSS的輔助方法。它不返回組件,而是直接將樣式添加到樣式表中
這個跟我們平時在寫html頁面,會先把一些需要重置瀏覽器的樣式加到頁面上的做法類似,主要作用是:重置樣式及書寫全局可共用的樣式
import { injectGlobal } from 'styled-components'; injectGlobal` @font-face { font-family: 'Operator Mono'; src: url('../fonts/Operator-Mono.ttf'); } body { margin: 0; } `;
# StyledComponent # 樣式化組件聲明方式:styled.tagname、styled(Component) 兩種方式
第一種直接通過styled點一個元素標簽,將button元素轉化成樣式化組件
第二種是重寫樣式化組件的部分樣式,比如TomatoButton
還有一種是將一個非樣式化組件轉換成樣式化組件並附加樣式,如使用的螞蟻金服的UI:Flex
import styled from 'styled-components';
import { Flex, List} from 'antd-mobile';
const Button = styled.button` background: palevioletred; border-radius: 3px; border: none; color: white; `; const TomatoButton = styled(Button)` background: tomato; `;
const MoneyDetail = styled(Flex).attrs({
direction: 'row',
justify: 'between',
})`
padding: 0.26rem;
`
另外介紹兩種方法
.extend:創建一個新的StyledComponent並且繼承它的規則
如:TomatoButton繼承了Button的樣式規則,並使用一些與顏色相關的樣式進行擴展(其實就是覆蓋了被繼承組件的某些樣式)。
const TomatoButton = Button.extend` color: tomato; border-color: tomato; `;
.withComponent 創建一個新的StyledComponent,並應用於其他的標簽或組件,且使用相同的樣式
如:用<a>標簽替換<button>標簽,但還是使用相同的樣式,相當於<button>有的樣式<a>標簽一樣都有
const Link = Button.withComponent('a')
# Supported CSS # 樣式化組件它支持所有的CSS及嵌套,如偽元素使用、選擇器使用、媒體查詢、css及css3的各類聲明樣式
const Example = styled.div` padding: 2em 1em; background: papayawhip; /* 偽元素使用:當鼠標懸浮在div塊上時顯示背景色palevioletred */ &:hover { background: palevioletred; } /* 媒體查詢:在屏幕小余600px的寬度下顯示以下樣式 */ @media (max-width: 600px) { background: tomato; &:hover { background: yellow; } } /*css選擇器使用:給當前div元素下的子元素p添加下划線的樣式*/ > p { text-decoration: underline; } `; render( <Example> <p>Hello World!</p> </Example> );
# Attaching additional props # 附加額外的 props,可以使用.attrs構造函數,將props(或“attributes”)附加到當前組件
比如:聲明一個input輸入框,用html方式寫就是:<input type="text" length="20" padding="10px"/>
而通過樣式化組件聲明input輸入框就可以按下面的寫法:
import styled from 'styled-components'; const Input = styled.input.attrs({ type: 'text', length: props => props.length || 10 })` background: palevioletred; border-radius: 3px; border: none; color: white; padding: ${props => props.padding} `;
<Input length="20" padding="10px">
實際上 attrs 方法就是一種添加屬性的方式,也可以接收組件傳過來的prop,如上面<Input>組件傳的padding、length屬性。
.attrs對象還可以接收函數:比如我們聲明一個按鈕,並給它添加一個點擊事件
const Button = styled.button.attrs({ onClick: props => props.onClick || null })` background-color: '#e1e1e1'; color: ${props => props.color || '#FFFFFF'}; width: ${props => props.width || '1.92rem'}; height: ${props => props.height || '0.64rem'}; font-size: ${props => props.fontSize || '0.24rem'}; border-radius: ${props => props.borderRadius || '0.02rem'}; padding: 0.08rem 0.12rem 0.08rem 0.12rem; ${props => props.style || ''} `
<Button onClick={() => {alert('點擊我啊!')}}>
另外列舉一個通過prop傳遞值優化樣式的方式
精靈圖片通過傳遞的prop值裁剪相應圖片:
聲明一個 <i>元素的樣式化組件,並附一張背景圖片,引用時分別給定不同圖片的裁剪位置,如:
position={{backgroundPosition:'center -0.52rem'}},在樣式聲明中通過 ${props => props.position} 獲取當前需要裁剪顯示的位置
const WayImage = styled.i` background-image:url('${require('./resources/provided.png')}'); background-size: 0.38rem 2.1rem; background-repeat: no-repeat; ${props => props.position}; width: 0.4rem; height: 0.42rem; display: inline-block; vertical-align: middle; ` <WayImage position={{backgroundPosition:'center -0.52rem'}}/> <WayImage position={{backgroundPosition:'center -1.1rem'}}/>