通过JS来管理样式CSS Modules及React实践

2020-10-151506次阅读javascriptReact

CSS Modules加入了局部作用域、依赖管理。可以有效避免全局污染和样式冲突,能最大化地结合现有CSS生态和JS模块化能力。

webpack中的css-loader自带了CSS Modules,通过简单的配置即可使用。

// webpack.config.js
const path = require('path')

module.exports = {
  entry: __dirname + '/src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true,
            }
          }
        ]
       }
    ]
  }
}
// 也可以使用下面这种写法
// loader: "style-loader!css-loader?modules"


// exclude排除及include包含,使用公共样式
// module: { 
//     loaders: [{ 
//       test: /\.jsx?$/, 
//       loader: 'babel', 
//     }, { 
//       test: /\.scss$/, 
//       exclude: path.resolve(__dirname, 'src/styles'), //排除styles文件夹内的scss文件,因为这是common公共样式
//       loader: 'style!css?modules&localIdentName=[name]__[local]!sass?sourceMap=true', 
//     }, { 
//       test: /\.scss$/, 
//       include: path.resolve(__dirname, 'src/styles'), //但给styles文件夹内的scss文件,使用style!css!sass loader
//       loader: 'style!css!sass?sourceMap=true', 
//     }] 
//   }

生成HTML为

<div id="root">
    <div>
        <button class="yTXmm0isaXExoYiZUvKxH">Submit</button>
    </div>
</div>
<!-- yTXmm0isaXExoYiZUvKxH为CSS Modules自动生成的class类名 -->

CSS Modules 对 CSS 中的 class 名都做了处理,使用对象来保存原 class 和混淆后 class 的对应关系。CSS Modules自动生成的class类名基本就是唯一的,大大降低了项目中样式覆盖冲突的几率。

 

定制class类名

css-loader默认的哈希算法是[hash:base64],从前面我们可以发现.primary 被编译成了 yTXmm0isaXExoYiZUvKxH 这样的字符串。这名字也没风格了别担心,css-loader 为我们提供了localIdentName参数指定生成的名字格式。localIdentName的默认值是[hash:base64]。

...

{
    loader: 'css-loader',
    options: {
        modules: true,
        localIdentName: '[name]__[local]--[hash:base64:5]'
    }
}

// 或者
loader: 'style-loader!css-loader?modules&localIdentName=[name]__[local]--[hash:base64:5]'
...

 

样式默认局部及开启CSS Modules全局样式

使用了CSS Modules后,样式默认给每个class名外加加了一个 :local,以此来实现样式的局部化,如果你想切换到全局模式,使用对应的 :global。

.normal {
  color: green;
}

/* 以上与下面等价 */
:local(.normal) {
  color: green; 
}

/* 定义全局样式 */
:global(.btn) {
  color: red;
}

/* 定义多个全局样式 */
:global {
  .link {
    color: green;
  }
  .box {
    color: yellow;
  }
}

 

CSS Modules结合React实践

/* dialog.css */
.root {}
.confirm {}
.disabledConfirm {}
import classNames from 'classnames';
import styles from './dialog.css';

export default class Dialog extends React.Component {
  render() {
    const cx = classNames({
      [styles.confirm]: !this.state.disabled,
      [styles.disabledConfirm]: this.state.disabled
    });

    return <div className={styles.root}>
      <a className={cx}>Confirm</a>
      ...
    </div>
  }
}

注意,一般把组件最外层节点对应的 class 名称为 root。这里使用了classnames库来操作 class 名。
如果你不想频繁的输入styles.**,可以试一下react-css-modules,它通过高阶函数的形式来避免重复输入styles.**。

上一篇: React HOOK中useEffect的使用  下一篇: Vue与React插槽区别  

通过JS来管理样式CSS Modules及React实践相关文章