#4 react-css-modules

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>
    )
  }
}

總結

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 無意中看到zhangwnag大佬分享的webpack教程感覺受益匪淺,特此分享以備自己日后查看,也希望更多的人看到...
    小小字符閱讀 8,383評論 7 35
  • 原文地址:react-css-modules閱讀本文前建議了解 CSS Modules 的知識。墻裂推薦閱讀 Ca...
    梁相輝閱讀 2,361評論 1 18
  • GitChat技術雜談 前言 本文較長,為了節(jié)省你的閱讀時間,在文前列寫作思路如下: 什么是 webpack,它要...
    蕭玄辭閱讀 12,916評論 7 110
  • 學習流程 參考文檔:入門Webpack,看這篇就夠了Webpack for React 一. 簡單使用webpac...
    Jason_Zeng閱讀 3,266評論 2 16
  • 小旺才: 我的腳要3周不能走路,這段時間要你自己去干很多事,一開始可能還要媽媽提醒一下,我想你會越干越好的。 昨天...
    樊里洋閱讀 277評論 2 3

友情鏈接更多精彩內(nèi)容