元のアドレス:react-css-modules
この記事を読む前に、CSS モジュールの知識を理解することをお勧めします。 Wall Crack は、Cam の記事 CSS モジュールの詳細な説明と React での実践を読むことをお勧めします。
React CSS Modules は、CSS モジュールの自動マッピングを実装します。各 CSS クラスには、グローバルに一意な名前を持つローカル識別子が割り当てられます。 CSS モジュールはモジュール性と再利用性を実現します。
CSS Mosules はブロックされています。 CSS モジュールに詳しくない方のために説明しておくと、これは webpack のようなモジュール バンドラーを使用して特定のドキュメントの CSS をロードするという単なる概念です。 CSS モジュール ローダーは、CSS ドキュメント (正確には、このドキュメントは相互運用可能な CSS) をロードするときに、CSS クラスごとに一意の名前を生成します。 CSS モジュールの実用的な例である webpack-demo をご覧ください。
React 構文環境では、CSS モジュールは次のようになります↘
import React from 'react';import styles from './table.css';export default class Table extends React.Component { render () { return <div className={style.table}> <div className={style.row}> <div className={style.cell}>A0</div> <div className={style.cell}>B0</div> </div> </div>;
コンポーネントがレンダリングされると、次のようなマークが生成されます↘
<div class="table__table___32osj"> <div class="table__row___2w27N"> <div class="table__cell___2w27N">A0</div> <div class="table__cell___1oVw5">B0</div> </div></div>
同時に、それらのCSSクラスに一致する対応するCSSファイルも生成されますが、これはブロッカーなのでしょうか? !
CSS モジュールは、さまざまな方法で実装できる仕様です。 act-css-modules は、webpack css-loader によって提供される機能を使用して、既存の CSS モジュールの統合を可能にします。
webpack css-loader 自体にはいくつかの欠点があります。
comelCaseCSS クラス名を使用する必要があります。
className を構築するときは常にスタイル オブジェクトを使用する必要があります。
Mixin クラス モジュールとグローバル CSS クラスは十分な柔軟性がありません。
未定義の CSS モジュールを参照すると、解析結果は undefine になりますが、関連する警告は表示されません。
React CSS Modules コンポーネントは CSS モジュールを自動的にロードし、styleName 属性を使用します。例:
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);
react-css-modules を使用すると多くの利点があります。 :
キャメルケースの命名規則を使用する必要がなくなりました。
スタイル オブジェクトを使用するたびにスタイル オブジェクトを参照する必要はありません。 CSSモジュール。
グローバル CSS と CSS モジュールには明らかな違いがあります。例は次のとおりです:
<div className='global-css' styleName='local-module'></div>
styleName が定義されていない CSS モジュールを参照すると、警告メッセージが表示されます。 (errorWhenNotFound オプション)
ReactElement ごとに個別の CSS モジュールを使用することができます。 (allowMultiple オプション)。
を実装すると、react-css-modules はターゲット コンポーネントの render メソッドを拡張します。 styleName の値に基づいて、関連付けられたスタイル オブジェクト内で対応する CSS モジュールを検索し、一致する一意の CSS クラス名を ReactElement className 属性値に追加します。
ブロックハウス!
この例、react-css-modules-examples を参照して、さらに印象を深めてください。
設定には以下が含まれます:
相互運用可能な CSS をロードするためのモジュール バンドラーを設定します。
コンポーネントをトリミングするには、react-css-modules を使用します。
開発環境でソースマップを有効にしたい場合は、webpack のホット モジュール交換 (HMR、ホット交換) を使用する必要があります。 style-loader はすでに HMR をサポートしています。したがって、ホットモジュール交換はすぐに機能します。
セットアップ手順:
スタイルローダーをインストールします。
css-loader をインストールします。
/.css$/ ローダーを次のように設定します:
{ test: /\.css$/, loaders: [ 'style?sourceMap', 'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]' ]}
プロダクション内環境で CSS を個別に抽出する場合は、その利点と欠点を理解する必要があります。
長所:
スタイルタグが少ない
CSS ソースマップ
CSS 並列リクエスト
CSS キャッシュ分離
ページレンダリングの高速化 (コードと DOM 操作の削減)
欠点:
追加の HTTP リクエスト
コンパイル時間が長い
詳細複雑な構成
実行環境のパブリック パスの変更をサポートしません
ホット モジュール交換をサポートしません
— 抽出テキスト-webpack-plugin
设置步骤:
安装 style-loader
安装 css-loader
使用 extract-text-webpack-plugin提取 CSS 到一个单独的样式表。
设置 /\.css$/加载器:
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]')}
设置 extract-text-webpack-plugin插件:
new ExtractTextPlugin('app.css', { allChunks: true})
完整实例请参照 webpack-demo或者 react-css-modules-examples。
Browserify(如果你是使用这个构建工具的话)
请参考 css-modulesify。
使用 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);
在这个例子中, CSSModules被用来美化 Table组件通过引用 ./table.cssCSS 模块。当 Table组件渲染完毕,它将使用 styles对象的属性构建 className的值。
使用 styles属性你可以覆盖组件默认的 styles对象。例如:
import customStyles from './table-custom-styles.css';<Table styles={customStyles} />;
Interoperable CSS可以 扩展其他 ICSS。利用这个功能可以扩展默认样式,例如:
/* table-custom-styles.css */.table { composes: table from './table.css';}.row { composes: row from './table.css';}/* .cell { composes: cell from './table.css';} */.table { width: 400px;}.cell { float: left; width: 154px; background: #eee; padding: 10px; margin: 10px 0 10px 10px;}
在这个例子中, table-custom-styles.css有选择的扩展了 table.css( Table组件的默认样式)。
这里是一个更直观的实践例子: UsingStylesProperty example`。
包装过的组件继承了 styles属性,该属性描述了 CSS 模块和 CSS 类之间的映射关系。
class extends React.Component { render () { <div> <p styleName='foo'></p> <p className={this.props.styles.foo}></p> </div>; }}
在上面示例中, styleName='foo'和 className={this.props.styles.foo}是等价的。
styles属性是为 Loops and Child Components实现组件包装而特意设计的!
styleName不能去定义一个由其他组件生成的 React元素的样式 。例如:
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; itemTemplate = (name) => { return <li styleName='item-template'>{name}</li>; }; return <List itemTemplate={itemTemplate} />; }}export default CSSModules(CustomList, styles);
上面的实例将不会工作。CSSModules 被用来包装 CustomList组件。然而,它是呈现 itemTemplage的列表组件。
为了解决这个问题,包装过的组件继承了样式属性,这样你可以将它作为一个常规的 CSS 模块对象来使用。因此,前面的例子可以改写为这样:
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; itemTemplate = (name) => { return <li className={this.props.styles['item-template']}>{name}</li>; }; return <List itemTemplate={itemTemplate} />; }}export default CSSModules(CustomList, styles);
在把子组件传递给渲染组件之前,如果你使用了 CSSMmodules包装这个子组件,那么你就可以在这个子组件内使用 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; itemTemplate = (name) => { return <li styleName='item-template'>{name}</li>; }; itemTemplate = CSSModules(itemTemplate, this.props.styles); return <List itemTemplate={itemTemplate} />; }}export default CSSModules(CustomList, styles);
/** * @typedef CSSModules~Options * @see {@link https://github.com/gajus/react-css-modules#options} * @property {Boolean} allowMultiple * @property {Boolean} errorWhenNotFound *//** * @param {Function} Component * @param {Object} defaultStyles CSS Modules class map. * @param {CSSModules~Options} options * @return {Function} */
你需要用 react-css-modules包装你的组件,例如:
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);
就这么简单!
顾名思义, react-css-modules和 ES7 decorators语法是兼容的。例如:
import React from 'react';import CSSModules from 'react-css-modules';import styles from './table.css';@CSSModules(styles)export default class extends React.Component { render () { return <div styleName='table'> <div styleName='row'> <div styleName='cell'>A0</div> <div styleName='cell'>B0</div> </div> </div>; }}
简直碉堡了!
这里有一个用 webpack 构建的示例,你可以看下 react-css-modules-examples
CSSModules函数提供了一些选项在第三个参数的位置上。
CSSModules(Component, styles, options);
或者作为第二个参数:
@CSSModules(styles, options);
默认: false。
允许多个样式模块名字。
当 false,以下会引起一个错误。
<div styleName='foo bar' />
默认: true。
当 styleName不能匹配到一个未定义的 CSS Module 时将抛出一个错误。
Interoperable CSS和 CSS 预处理器是兼容的。使用预处理器,你只需添加这个预处理器到 loaders的数组中即可。例如在这个 webpack 的例子中,它就像安装 sass-loader一样简单,添加 !sass到 style-loader加载器查询的末尾(加载器是从右到左被依次执行的):
{ test: /\.scss$/, loaders: [ 'style', 'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]', 'resolve-url', 'sass' ]}
开启 CSS Source maps,需要在 css-loader和 sass-loader中添加参数 sourceMap
{ test: /\.scss$/, loaders: [ 'style?sourceMap', 'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]', 'resolve-url', 'sass?sourceMap' ]}
CSS Mosules 促进了类组合模式,也就是说,每一个用在组件里的 CSS Module 应该定义描述一个元素所需的全部属性。如:
.box { width: 100px; height: 100px;}.empty { composes: box; background: #4CAF50;}.full { composes: box; background: #F44336;}
类组合促进了标记和语义化样式更好的分离,如果没有 CSS Modules,这点将难以实现。
因为 CSS Module 中的类名是本地的,允许你使用诸如 'empty' 或 'full' 这些通用的类名,而无需再加上'box-' 前缀,简直完美!!
想学更多的类组合规则?我建议你读下 Glen Maddern 的关于 CSS Modules的文章,还有官方文档 spec of the CSS Modules。
设想下有这么个例子:
.box { width: 100px; height: 100px;}.box-empty { background: #4CAF50;}.box-full { background: #F44336;}
<div class='box box-empty'></div>
这是标准的 OOCSS 模式,这种模式最大的问题就是,如果你想改变样式,你几乎每次还要修改 HTML。
接下来是一个学习实践,以加深对类组合本质的理解。CSS Modules 支持一个本机方法,该方法是要组合的 CSS Mosules 使用 composes关键字实现的。CSS 预处理不是必须的。
在 SCSS 中你可以使用 @extend关键字,和使用 Mixin Directives去写组合,例如:
使用 @extend:
%box { width: 100px; height: 100px;}.box-empty { @extend %box; background: #4CAF50;}.box-full { @extend %box; background: #F44336;}
编译后,得到:
.box-empty,.box-full { width: 100px; height: 100px;}.box-empty { background: #4CAF50;}.box-full { background: #F44336;}
使用 mixins :
@mixin box { width: 100px; height: 100px;}.box-empty { @include box; background: #4CAF50;}.box-full { @include box; background: #F44336;}
编译后,得到:
.box-empty { width: 100px; height: 100px; background: #4CAF50;}.box-full { width: 100px; height: 100px; background: #F44336;}
CSS Modules 不会限制你使用全局 CSS。用法如下:
:global .foo {}
但是呢,还是请你谨慎使用全局样式。在使用 CSS Modules 过程中,只有少数情况下才会用到全局样式,例如: normalization。
避免使用多个 CSS Modules 去描述单个元素。详见本文档前面的 类组合部分介绍。
但是如果你非要使用多个 CSS Modules 去描述一个元素,那么就开启 allowMultiple选项。(参见文档前面 选项部分)。当多个 CSS Modules 被用来描述一个元素时, react-css-modules将会为每一个在 styleName声明中匹配的 CSS Module 附加一个独一无二的类名。如:
.button {}.active {}
<div styleName='button active'></div>
这会把Interoperable CSS 和 CSS class 都映射到目标元素上。