css的样式应用是全局性的,没有作用域可言,为了解决这个问题,社区出现了几套解决方案,第一种是通过人工的方式来约定命名规则,第二种是CSS Modules,第三种是CSS-in-JS,本文不讨论三种方案的优劣,而是给出一种约定命名规则的实践。
不知道BEM规范请点 这里
- 定义工具函数bem
// utils.js
const ELEMENT = '__';
const MODS = '--';
const join = (name, el, symbol) => (el ? `${name}${symbol}${el}` : name);
const prefix = (name, mods) => {
if (!mods) {
return name;
}
if (typeof mods === 'string') {
return join(name, mods, MODS);
}
if (Array.isArray(mods)) {
return mods.map(item => prefix(name, item)).join(' ');
}
const ret = [];
Object.keys(mods).forEach(key => {
if (mods[key]) {
ret.push(prefix(name, key));
}
});
return ret.join(' ');
};
/**
* bem helper
* @param {string} block
* eg.
* bem('header')('title') => 'header__title'
* bem('header')('title', 'active') => 'header__title--active'
*/
const bem = block => (el, mods) => {
const _el = join(block, el, ELEMENT);
return mods ? [_el, prefix(_el, mods)].join(' ') : _el;
};
export default bem;
- 在scss中定义前缀,并顺手导出
// scss
$class-prefix: 'dashboard';
.#{$class-prefix}--remark {
position: relative;
width: 100%;
height: 100%;
display: flex;
}
:export {
prefixCls: #{$class-prefix};
}
- 引入scss中的前缀和工具函数,调用bem生成辅助方法,在jsx中调用辅助方法生成真正的className
import { bem } from 'utils';
import { prefixCls } from './index.scss';
const cls = bem(prefixCls);
render() {
return <div className={cls('remark')} />
}
优点:
- 如果发现这个模块的css有冲突,只需要改一下index.scss中的前缀变量,所有地方的类名都会获得更新。
- css前缀与js变量打通,通过辅助方法bem,不需要在jsx写入冗长的类名。
缺点: