網站首頁 編程語言 正文
正文
目前,前端最流行的開發方式是組件化,而CSS的設計本身就不是為組件化而生的,所以在目前組件化的框架中都在需要一種合適的CSS解決方案
在組件化開發環境下的CSS,應該滿足如下需求:
- 可以編寫局部css: css具備自己的具備作用域,不會隨意污染其他組件內的元素
- 可以編寫動態的css: 可以獲取當前組件的一些狀態,根據狀態的變化生成不同的css樣式
- 支持所有的css特性:偽類、動畫、媒體查詢等
- 編寫起來簡潔方便、最好符合一貫的css風格特點
- 等等 。。。。
Vue在CSS上雖然不能稱之為完美,但是已經足夠簡潔、自然、方便了,至少統一的樣式風格不會出現多個開發人員、多個項目 采用不一樣的樣式風格
相比而言,React官方并沒有給出在React中統一的樣式風格
由此,從普通的css,到css modules,再到css in js,有幾十種不同的解決方案,上百個不同的庫
大家一致在尋找最好的或者說最適合自己的CSS方案,但是到目前為止也沒有統一的方案
內聯樣式
內聯樣式是官方推薦的一種css樣式的寫法:
- style 接受一個采用小駝峰命名屬性的 JavaScript 對象,而不支持 CSS 字符串形式寫法
- 并且可以引用state中的狀態來設置相關的樣式
優點
- 內聯樣式, 樣式之間不會有沖突
- 可以動態獲取當前state中的狀態
缺點
- 寫法上都需要使用駝峰標識
- 某些樣式沒有提示
- 大量的樣式, 代碼混亂
- 某些樣式無法編寫(比如偽類/偽元素)
所以官方依然是希望內聯合適和普通的css來結合編寫
import React, { PureComponent } from 'react'
export class App extends PureComponent {
constructor(props) {
super(props)
this.state = {
color: 'red'
}
}
render() {
return (
<div style={{ colot: this.state.color, backgroundColor: 'skyblue' }}>App</div>
)
}
}
export default App
普通的CSS
普通的css我們通常會編寫到一個單獨的文件,之后再進行引入
這樣的編寫方式和普通的網頁開發中編寫方式是一致的
但是使用這種方式編寫我們的css有一個致命缺點,即沒有自己的樣式作用域
默認引入的樣式都是全局樣式
import React, { PureComponent } from 'react'
import './style.css'
export class App extends PureComponent {
constructor(props) {
super(props)
this.state = {
color: 'red'
}
}
render() {
return (
<div>App</div>
)
}
}
export default App
css modules
css modules并不是React特有的解決方案,而是所有使用了類似于webpack配置的環境下都可以使用的
如果在其他項目中使用它,那么我們需要自己來進行配置,比如配置webpack.config.js中的modules: true等
如果使用React腳手架,其內部已經內置了css modules的配置
.css/.less/.scss 等樣式文件都需要修改成 .module.css/.module.less/.module.scss 等 之后就可以引用并且進行使用了
import React, { PureComponent } from 'react'
// 引入css modules - 實際會將對應的css文件編譯為一個JS對象
// 當我們將一個樣式文件的后綴名修改為 .module.css的時候,對應樣式文件就變成了css樣式模塊
import AppStyle from './style.module.css'
export class App extends PureComponent {
constructor(props) {
super(props)
this.state = {
color: 'red'
}
}
render() {
return (
<div>
{/*
css modules 會將css文件編譯為js對象,所以需要向屬性那樣使用
同理 如果使用了一個樣式模塊中不存在的樣式,對應值就是undefined
實際表現為對應元素樣式不生效, 頁面并不會報錯
*/}
<h2 className={AppStyle.title}>title</h2>
{/*
對應的樣式會被編譯w為 style_content__O3F7P
也就是 [樣式文件名]_[樣式名]__[hash值]
從而避免出現樣式沖突
*/}
<p className={AppStyle.content}>content</p>
</div>
)
}
}
export default App
但是CSS modules依舊存在自己的缺點
- 引用的類名,不能直接使用連接符(.home-title),需要使用中括號語法,因為連字符在JavaScript中是不識別的
- 所有的className都必須使用{style.className} 的形式來編寫
- 不方便動態來修改某些樣式,依然需要使用內聯樣式的方式
css in js
“CSS-in-JS” 是指一種模式,其中 CSS 由 JavaScript 生成而不是在外部文件中定義
注意此功能并不是 React 的一部分,而是由第三方庫提供
React的思想中認為邏輯本身和UI是無法分離的,所以才會有了JSX的語法
事實上CSS-in-JS的模式就是一種將樣式(CSS)也寫入到JavaScript中的方式,并且可以方便的使用JavaScript的狀態
所以React有被人稱之為 All in JS
CSS-in-JS通過JavaScript來為CSS賦予一些能力,包括類似于CSS預處理器一樣的樣式嵌套、函數定義、邏輯復用、動態修 改狀態等等
所以,目前可以說CSS-in-JS是React編寫CSS最為受歡迎的一種解決方案
目前最為常用的css-in-js庫是 styled-components
npm install styled-components
組件
import React, { PureComponent } from 'react'
// 使用css in js后,對應的樣式直接編寫在js文件中即可
import AppWrapper from './style.js'
export class App extends PureComponent {
render() {
return (
<AppWrapper>
<h2 className="title">title</h2>
<p className="content">content</p>
</AppWrapper>
)
}
}
export default App
樣式
import styled from 'styled-components'
// styled.div本質上是一個函數 需要通過標簽模板字符串進行調用 并返回一個新的有對應樣式的組件
// ps: 默認情況下對應樣式是不會高亮的,需要高亮可以安裝vscode-styled-components插件
export default styled.div`
/* 對應樣式會被編譯為 .jaGVDq */
/* 即一個唯一的hash值 */
/* 所以使用styled-components編寫對應的樣式會存在自己的樣式作用域 */
/* 組件和組件之間的樣式是不會沖突的 */
/*
但因為編譯后的樣式類似于 .jaGVDq .content
所以在實際使用過程中,對于后代選擇器仍然可能出現樣式沖突的情況
*/
background-color: #f5f5f5;
/* .jaGVDq .title */
.title {
color: red;
&:hover {
background-color: gray;
}
}
/* .jaGVDq .content */
.content {
color: skyblue
}
`
樣式組件
import styled from 'styled-components'
export default styled.div`
background-color: #f5f5f5;
.content {
color: skyblue
}
`
// 如果某一塊的樣式比較多,可以將對應的樣式進行單獨抽離
// 形成一個獨立的樣式組件
export const TitleWrapper = styled.h2`
color: red;
&:hover {
background-color: gray;
}
`
引入外部變量
import React, { PureComponent } from 'react'
import AppWrapper from './style.js'
export class App extends PureComponent {
constructor(props) {
super(props)
this.state = {
color: 'skyblue'
}
}
render() {
return (
// AppWrapper本質上是一個組件
// 所以對應的樣式直接以props的形式進行傳入即可
<AppWrapper color={ this.state.color }>
<h2 className="title">title</h2>
<p className="content">content</p>
</AppWrapper>
)
}
}
export default App
import styled from 'styled-components'
export default styled.div`
.title {
/*
如果直接使用props.color 在js中 會沿著作用域鏈去查找對應的props
所以直接使用props 在css in js中是不合適的
所以在styled-components中引入外部變量的時候,需要傳入一個回調函數
該回調函數的參數為外部傳入的props,返回值是所需要設置的對應樣式值
*/
color: ${ props => props.color };
&:hover {
background-color: gray;
}
}
.content {
color: gray
}
`
默認值
import styled from 'styled-components'
// 因為styled-components 本質上就是css in js
// 所以我們也可以通過如下方式來使用styled-components
export default styled.div`
.title {
// 解構語法
color: ${ ({ color }) => color };
&:hover {
// 解構的時候 設置對應的默認值
background-color: ${ ({ bgColor = 'yellow' }) => bgColor };
}
}
.content {
// 空值合并操作符
color: ${ ({ contentColor }) => contentColor ?? 'orange' }
}
`
有的時候,我們希望在外部沒有傳入對應props的時候,可以存在對應的默認值
但是使用上述寫法,每使用一次就需要單獨設置一次對應的默認值,這必然是十分麻煩的
所以styled-components提供了attrs方法,專門用于設置默認值
import styled from 'styled-components'
// attrs方法會返回對應的含有樣式的樣式組件
// 所以在這里可以鏈式調用
// 在attrs中可以傳入一個回調函數,用于設置對應的默認值
// 回調函數在被調用的時候會將對應的props傳遞過來
export default styled.div.attrs(props => ({
contentColor: props.contentColor ?? 'purple'
}))`
.title {
color: ${ props => props.color };
&:hover {
background-color: gray;
}
}
.content {
color: ${ props => props.contentColor }
}
`
引入全局樣式
/style/theme.js --- 全局的主題樣式文件
export const primaryColor = '#409eff'
export const warnColor = '#e6a23c'
export const successColor = '#67c23a'
樣式組件
import styled from 'styled-components'
import {
primaryColor,
successColor
} from '../style/theme'
export default styled.div`
.title {
color: ${ successColor };
&:hover {
background-color: gray;
}
}
.content {
color: ${ primaryColor }
}
`
provider
app.jsx
import ReactDOM from 'react-dom/client'
import App from './App'
import { StrictMode } from 'react'
import { ThemeProvider } from 'styled-components';
ReactDOM.createRoot(document.querySelector('#root')).render(
<StrictMode>
{/*
ThemeProvider 是 styled-components中 導出的 context
通過theme屬性來設置對應的全局變量值
*/}
<ThemeProvider theme={{ color: 'skyblue' }}>
<App />
</ThemeProvider>
</StrictMode>
)
import styled from 'styled-components'
export default styled.div`
.title {
/* ThemeContext中提供的全局樣式值會被傳入到 props.theme中 */
color: ${ props => props.theme.color };
}
.content {
color: red
}
`
樣式繼承
const OriginButton = styled.button`
border-radius: 5px;
`
export const PrimaryButton = styled(OriginButton)`
color: #fff;
background-color: #409eff;
`
動態添加class
寫法一 --- 使用三元運算符
import React, { PureComponent } from 'react'
export class App extends PureComponent {
constructor(props) {
super(props)
this.state = {
isActive: true,
isCurrent: true
}
}
render() {
const { isActive, isCurrent } = this.state
return (
<div>
<div className={ `${isActive ? 'active' : '' } ${ isCurrent ? 'current' : '' }` }>active</div>
</div>
)
}
}
export default App
寫法二 --- 使用join方法
import React, { PureComponent } from 'react'
export class App extends PureComponent {
constructor(props) {
super(props)
this.state = {
isActive: true,
isCurrent: true
}
}
render() {
const { isActive, isCurrent } = this.state
const activeClass = []
if (isActive) {
activeClass.push('active')
}
if (isCurrent) {
activeClass.push('current')
}
return (
<div>
<div className={ activeClass.join(' ') }>active</div>
</div>
)
}
}
export default App
寫法三 --- 使用第三方庫 classnames
npm install classnames
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
// classnames 支持多種編寫方式 混合使用
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'
// 只要是falsy值的結果 全部都會被忽略
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
// classnames 支持 數組寫法 和 計算屬性名
className={ classnames([{ [activeClass]: isActive }, { current: isCurrent }])
原文鏈接:https://juejin.cn/post/7140437664771080205
相關推薦
- 2022-09-16 C語言庫函數getchar()新見解_C 語言
- 2022-05-04 redis?zset實現滑動窗口限流的代碼_Redis
- 2022-12-04 pyecharts如何實現顯示數據為百分比的柱狀圖_python
- 2022-10-08 Pandas數據分析-pandas數據框的多層索引_python
- 2022-06-14 golang連接redis庫及基本操作示例過程_Golang
- 2022-04-28 Android?連接藍牙掃碼器無輸入框的實現_Android
- 2023-09-12 spring webflux配置成tomcat的線程池
- 2022-08-27 C++?Thread實現簡單的socket多線程通信_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支