一文了解react中定義樣式(css/less/sass)的常用方法


react中通過jsx的語法方式,將html標簽和js語法聯系在一起,而css的編寫方式,沒有明確的指定編寫方式,目前就有很多不同方法,每個方式各有其優缺點,我們一起來看看常用的定義方式有哪些。

最基礎也是最簡單的方式就是如html當中編寫樣式一樣,直接內聯使用,區別在於jsx中內聯使用樣式需要用小駝峰命名,不可使用短橫線 -,jsx中編寫js的表達式需要使用 {},而定義的樣式是以對象的形式存在,也是通過{},所以看起來style標簽里面使用了兩個大括號{}

return(<div style={{color: 'blue'}}>
   hello react
</div>)

這樣的方式優點是代碼不會沖突,定義的代碼都作用於當前元素,而且如果需要動態的獲取state的值來設置樣式也可以做到。缺點也很明顯,當如果樣式非常多的時候,即使把樣式整體提煉出來,作為一個變量賦值給style,但仍然還是和業務邏輯混雜在一起,並且無法編寫偽類等一些語法。第二種方式能夠將css代碼與業務邏輯代碼分離開來,在jsx的標簽中定義className屬性,自定義css的樣式文件,再通過import引入css/scss/less等樣式文件,就是使用的css的原生編寫方式,定義偽類以及其它的高級選擇器編寫方式都可以支持。

return(<div className="title">
   hello react
</div>)

// 定義在單獨的樣式文件
.title {
    color: 'blue'
}

這樣可以讓代碼比較清晰明了,css樣式和jsx文件分離開。

當需要使用多個className,或者通過狀態來變更className時,可以通過+來進行字符串拼接,或者使用數組,再通過toString()轉成字符串

const isActive = true
<h2 className="active foo bar">我是標題1</h2>       
// active foo bar   
<h2 className={"foo", (isActive ? "active" : "") }>我是標題2</h2>  
// active
<h2 className={"foo" + (isActive ? " active" : "") }>我是標題3</h2> 
// foo, active
<h2 className={["foo",(isActive ? "active" : "")]}>我是標題4</h2>  
// foo, active
<h2 className={["foo",(isActive ? "active" : "")].join(" ")}>我是標題5</h2> 
// foo avtive

為了簡便使用,可以直接使用 classnames 這個庫來動態的使用類名,classnames默認暴露了一個函數,傳入參數的參數可以為字符串、對象和數組,傳入null/undefined/boolean值也不會顯示在頁面上

import classNames from 'classnames'
const isShow = false
const list = ['foo', 'bar']
<h2 className={classNames({"active": isActive}, "foo")}>我是標題6</h2>    
// active foo
<h2 className={classNames({"active": isActive, "bar": isShow })}>我是標題7</h2> 
// active 
<h2 className={classNames({"active": isActive}, list)}>我是標題8</h2>       
// active foo bar
<h2 className={classNames(null, undefined, 0, 10, '0', true, false)}>我是標題8</h2> 
// 10 0

但react開發的頁面都叫做單頁面應用,整個項目只有一個頁面,樣式在a組件引用,b組件即使沒有引用,定義了同名的類名,也會有樣式,這樣導致如果c組件和d組件都定義了className屬性,分別引入了css樣式定義字體顏色,但最終兩者呈現出的字體顏色為后引入的css文件里的字體顏色,即同名的樣式會被覆蓋掉。

為了解決這一問題,我們就需要在跟標簽處再定義一個className,來包裹當前組件的所有標簽,這樣css樣式的層級就比較多,並且還可能因為選擇器優先級的問題(在外層定義了id選擇器),而產生樣式沖突,同時它不支持獲取state屬性動態設置樣式。

return(<div className="homeComponent">
    <div className="title">hello react</div>
</div>)

此時就產生了第三種編寫方式,css的模塊化,這樣的方式可以區分各個組件的樣式,不會相互覆蓋,而且還能定義偽類,react腳手架當中內置了css modules的配置,我們可以直接將css的文件定義為 xxx.module.css,在xxx.module.css文件中,還是按照以前的css編寫方式編寫,不同點在於jsx頁面中定義className,先引入該css文件,然后定義類名以對象的形式定義

import style from './index.module.css'
return(<div className={style.title}>
    hello react
</div>)

這樣定義的樣式是一個不會重復的字符


這樣一種定義樣式的方式能夠比較有效的解決樣式重疊的問題,麻煩之處就是每次編寫樣式的時候需要通過對象的語法來定義,並且不支持動態的設置樣式。

那么就有了第四種方式,css in js,這是一種代碼的理念,react中html和js沒有分離,那么css也可以不分離,以js的方式來編寫css,使css的編寫更加的靈活,既可以像之前寫css一樣編寫,又可以動態的獲取屬性。這種編寫方式需要依賴其它庫,這里使用常用的 styled-components來演示。

使用 styled-components之前需要對es6模板字符串的一種語法有了解,我們可以使用模板字符串來對字符串和屬性進行拼接,在此之前的拼接可能都需要使用 +

const name = 'kiki'
const age = '18'
const user = `my name is ${name}, age is ${age}`
console.log(user) // my name is kiki, age is 18

但模板字符串還有一種用法,就是它可以像小括號一樣調用函數,並且參數以一定的規則傳遞給函數

let name = 'kiki', age = 18
function foo(...args){
   console.log(args)
}
foo`hello`
foo`my name is ${name}, age is ${age} `

 

基於模板字符串的這種使用方式,我們來看看 styled-components 如何使用,先從styled-components的默認暴露中引入函數,創建一個div標簽,並在模板字符串中定義樣式,最后將創建的組件替換div標簽,通過js定義的組件都可以抽取到一個單獨的js文件當中,這里為了演示方便,就寫在了一起。
import React, { PureComponent } from 'react'
import styled from 'styled-components'

const DivStyle = styled.div`
  background-color: gray;
  color: #fff;
  font-size: 20px;
`

export default class Profile extends PureComponent{
  render(){
    return(<div>
      <DivStyle>我是Profile組件的內容</DivStyle>
    </div>)
  }
}

這樣看起來編寫方式更為復雜了,但其實它還有很多好用的方式,除了使用樣式,我們可能還對有些標簽要做一些別的屬性設置,以及我們需要通過當前頁面維護的state屬性來區分樣式的展示,在定義樣式的時候,value值以函數的形式從props中獲取屬性

import React, { PureComponent } from 'react'
import styled from 'styled-components'

const InputStyle = styled.input.attrs({
  type: 'text',
  placeholder: '請輸入內容',
})`
  color: ${props => props.color}
`

export default class Deliver extends PureComponent{
  constructor(props){
    super(props)
    this.state = {
      color: 'purple'
    }
  }

  render(){
    return(<p>
      <InputStyle type="password" color={this.state.color}/>
    </p>)
  }
}

樣式當中,如果有重復的定義樣式方式,要么需要定義多個className,要么就得重復定義,styled-components提供了繼承的方式使樣式可以復用,通過styled-components中默認暴露的導出函數,直接傳入已定義好樣式的組件

import React, { PureComponent } from 'react'

import styled from 'styled-components'

const DivStyle = styled.div`
  background-color: gray;
  color: #fff;
  font-size: 14px;
`
const RecommondStyle = styled(DivStyle)`
  font-size: 20px;
`

export default class Profile extends PureComponent{
  render(){
    return(<div>
        <DivStyle>    
          hello styled-components
        </DivStyle>
        <RecommondStyle>
          style屬性的繼承
        </RecommondStyle>
      </div>
    )
  }
}

另外,還可以給最外層的組件定義一個主題,這樣它定義的樣式子元素都可以從props中獲取到

// 父組件
import { ThemeProvider } from 'styled-components'

export default class Home extends PureComponent{
  render(){
    return(<ThemeProvider theme={{color: 'brown'}}>
      <About/>
    </ThemeProvider>)
  }
}

// 子組件
import React, { PureComponent } from 'react'
import styled from 'styled-components'

const DivStyle = styled.div`
  color: ${props => props.theme.color};
`

export default class About extends PureComponent{
  render(){
    return(<DivStyle>
        style設置主題
      </DivStyle>   
    )
  }
}

這樣一種css的編寫方式使得css的代碼更像js,非常的靈活,也更具有復用性。

以上四種樣式在react當中的定義方式是比較常用的,可以根據情況結合使用~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM