CSS Modules
在React中寫樣式有多種方式,比較常見的有 CSS modules,這種方法將css樣式和組件放在一起,然后組件中直接應用,目錄結構:
|—src
| |_components
| |_ButtonComponent
| |_Button.jsx
| |_button.sass
具體示例: css mudules in react
可以看出通過模塊應用的樣式都是通過這樣的形式:
# 1.先引入對應模塊的樣式
import styles from './GlobalSelectors.css';
# 2.使用 className={styles.container} 這種形式表示模塊class名
# 而 className="text-left" 這種形式則表示全局下的選擇器
export default class GlobalSelectors extends Component {
render() {
return (
<div className={ styles.container }>
<p className="text-left">Global Selectors</p>
</div>
);
}
}
// css文件為 GlobalSelectors.css
.container {
border-width: 2px;
border-style: solid;
border-color: brown;
padding: 0 20px;
margin: 0 6px;
max-width: 400px;
}
# ':global' 表示該類為全局作用域下的
.container :global .text-left {
float: left
}
css modules本身需要css-loader來配合,這可能會出現(xiàn)的缺點:
- 必須使用
camelCase來命名 css class names - 當引入到
className中時必須要使用 styles 對象 - CSS modules 和 全局css類混合在一起會很難管理
- 引用沒用定義的CSS modules不會出現(xiàn)警告
而react css Modules組件通過 styleName 將自動的加載CSS MODULES.
react-css-modules
使用react-css-modules將解決上面css modules的問題,例如:
import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './tabel.sass'
class Table extends React.Component {
render() {
return (
# className 表示全局類名
# styleName 表示模塊類名
<div styleName="table" className="tabel--info">
<div styleName="row">
<div styleName="cell">A0</div>
<div styleName="cell">B0</div>
</div>
</div>
);
}
}
# CSSModules 對組件進行修飾
export default CSSModules(Table, styles);
下面談具體實現(xiàn)步驟和注意事項
1.安裝
通過npm安裝:
npm install --save react-css-modules
2.webpack配置
這個包需要用到 style-loader | css-loader
1.對css文件進行配置
對于開發(fā)階段:
# 注意 loaders 為復數(shù)
{
test: /\.css$/,
loaders: [
'style?sourceMap',
'css?modues&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]'
]
}
對于產(chǎn)品階段: 使用2.x版本 extract-text-webpack-plugin
npm install --save-dev extract-text-webpack-plugin@2
npm install --save-dev resolve-url-loader post-loader
// webpack.config.js file
var ExtractTextPlugin = require('extract-text-webpack-plugin');
# 注意 loader 為單數(shù)
{
test: /\.css$/,
loader: ExtractTextPlugin({
notExtractLoader: 'style-loader',
loader: 'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base4:5]!resolve-url!postcss'
})
}
# 配置ExtractTextPlugin
plugins: [
// ...
new ExtractTextPlugin({
filename: 'app.css',
allChunks: true
})
]
2.對于使用sass或其它預處理器
安裝需要的加載器:
npm install --save-dev resolve-url-loader sass-loader node-sass
// 不使用sourceMap
{
test: /\.sass$/,
loaders: [
'style',
'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
'resolve-url',
'sass'
]
}
// 使用sourceMap
{
test: /\.sass$/,
loaders: [
'style?sourceMap',
'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
'resolve-url',
'sass?sourceMap'
]
}
當然產(chǎn)品階段的配置也類似
3.使用 'styles' 重寫組件樣式
比如:
import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './table.css';
class Table extends React.Component {
render () {
return <div styleName='table'>
<div styleName='row'>
<div styleName='cell'>A0</div>
<div styleName='cell'>B0</div>
</div>
</div>;
}
}
export default CSSModules(Table, styles);
這是常見寫法,如果要重寫styles中樣式, 可以在組件中使用 styles 來重寫組件樣式:
# 引入自定義樣式
import customStyles from './table-custom-styles.css';
# 使用 styles屬性來重寫之前的樣式
<Table styles={customStyles} />
4. 循環(huán)和子組件
styleName 不能用來修飾組件中的子組件,比如:
import React from 'react';
import CSSModules from 'react-css-modules';
import List from './List';
import styles from './table.css';
class CustomList extends React.Component {
render () {
let itemTemplate;
# 使用styleName 來修飾CustomList組件的子組件List
# 這是不允許的
itemTemplate = (name) => {
return <li styleName='item-template'>{name}</li>;
};
return <List itemTemplate={itemTemplate} />;
}
}
export default CSSModules(CustomList, styles);
可以通過下面2種方法來改寫:
方法1:使用 styles 屬性
import React from 'react';
import CSSModules from 'react-css-modules';
import List from './List';
import styles from './table.css';
class CustomList extends React.Component {
render () {
let itemTemplate;
# 使用styles屬性,從父組件傳遞下去即可
itemTemplate = (name) => {
return <li className={this.props.styles['item-template']}>{name}</li>;
};
return <List itemTemplate={itemTemplate} />;
}
}
export default CSSModules(CustomList, styles);
方法2: 在父組件內(nèi)部調(diào)用CSSModules, 對子組件進行修飾:
import React, {Component} from 'react';
impot CSSModules from 'react-css-modules';
import List from './List';
import styles from './tabel.css';
class CustomList extends Component {
render() {
let itemTemplate;
itemTemplate = (name) => {
return <li styleName="item-template">{name}</li>;
};
# 內(nèi)部調(diào)用CSSModules
itemTemplate = CSSModules(itemTemplate, this.props.styles);
return <List itemTemplate={itemTemplate} />;
}
}
export default CSSModules(CustomList, styles);
5.CSSModules選項
CSSModules有2種寫法:
CSSModules(Component, styles, options)
// 或者
CSSModules(Component, styles)
options :
1.allowMultiple: 默認值為false
是否允許聲明多個類, false則表示不允許:
<div styleName='foo bar' /> // 不允許則報錯
2.errorWhenNotFount: 默認值為 true,
如果styleName在 css modules中沒有找到則會報錯
6.使用global css
:global .foo {
// ...
}
這種使用的比較少
7.對于選擇性的類名使用styles屬性
我們經(jīng)常會碰到這樣的類名情況:
<div className={this.props.showMsg ? 'msg--visble': 'msg--hidden'}>
</div>
使用react-css-modules如何處理這種問題呢?
關鍵在于被CSSModules裝飾的組件繼承 styles 屬性, 用來映射css modules 和 css classes,即:
class App extends React.Component {
render() {
<div>
<p styleName='foo'></p>
<p className={this.props.styles.foo}></p>
</div>
}
}
在這個例子中,styleName='foo' 和 className={this.props.styles.foo} 是等同的?。?!
所以上面問題的解決辦法就是:
class App extends Component {
// ...
render() {
# 先聲明這個變量
let visible = this.props.showMsg ? 'msg-visible' : 'msg-hidden';
return (
<div
# 然后在這用className來代替styleName
# 注意因為visible含有 '-'等字符,所以使用[]的方式
className={this.props.styles[visible]}
>
...
</div>
)
}
}
總結
- react-css-modules github
- css modules examples
- 學習當className隨事件變化時的寫法(第7條)
- 主要目的學習以下react中書寫樣式的一種方式
- webpack中如何配置css相關的loaders