classNames模块

作者:ManfredHu
链接:http://www.manfredhu.com/2016/07/12/21-classNames/index.html
声明:版权所有,转载请保留本段信息,谢谢大家

classNames

classNames

今天分享一个好玩的东西,它叫 classNames ,这个是一个翻译的版本,原版链接在这里它是一个小工具。我是在React项目里面用到它的。一用就停不下来了

它是什么?

它是一个简单的对类名进行条件判断并且拼装的小工具。通过条件判断把对应的class串接起来,可以更清晰的展示组件的状态对应的css.
总的来说,就是让你的代码可读性更高

它用在哪里?

React官方推荐用它,当然,既然是小工具,那么肯定扩展性是非常强的。不仅仅是React!!不仅仅是React!!不仅仅是React!!重要的事情我们说三遍

为什么要用它?

项目CSS代码的规范遵循的是BEM,所以我们有很多的类名是有状态定义的,比如 .sidebar__item--active 。你应该可以一眼看出来,这是一个侧边导航栏的激活状态,在选中的时候显示。但是通常还有一个默认状态 .sidebar__item ,那么这个时候,你通常会加多一个判断语句,因为你需要判断是不是激活的。

侧边栏激活状态

1
2
3
4
5
6
7
8
9
10
var SideBar = React.createClass({
// ...
render () {
var sideBarClass = 'sidebar__item';
if (this.state.isActive) {
sideBarClass += '--active';
}
return <div className={sideBarClass}>{this.props.text}</div>;
}
});

那么假设你还有一个自定义颜色的 .sidebar__item-orange 类。
那你的代码会多一个 if 判断.

1
2
3
4
5
6
7
8
9
10
11
12
13
var SideBar = React.createClass({
// ...
render () {
var sideBarClass = 'sidebar__item';
if (this.state.isActive) {
sideBarClass += '--active';
}
if (this.props.color) {
sideBarClass += '' + this.props.color; //'+'优先于'+='
}
return <div className={sideBarClass}>{this.props.text}</div>;
}
});

假如……好了没那么多假如了,你的类名有多长,你的 if 就会有多长。
所以作为一个有追求的前端,不能忍!!

不能忍

怎么用?

还是上面的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var cl = require('classnames');
var SideBar = React.createClass({
// ...
render () {
var sideBarClass = cl({
'sidebar__item': true,
'--active': this.state.isActive,
[this.props.color] :this.props.color, //这里用的是ES6的语法,可以用JSX编译工具如babel转换出来
....
....
....
});
return <div className={sideBarClass}>{this.props.text}</div>;
}
});

有多少可以来多少,不怂好吗。
引用了一个模块,我们的代码就优雅了好多了,可能你还会担心,这模块大不大啊,引入的话会不会得不偿失啊。我们看一下源代码吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
(function () {
var hasOwn = {}.hasOwnProperty;
function classNames () {
var classes = [];
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (!arg) continue;
var argType = typeof arg;
if (argType === 'string' || argType === 'number') {
classes.push(arg);
} else if (Array.isArray(arg)) {
classes.push(classNames.apply(null, arg));
} else if (argType === 'object') {
for (var key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes.push(key);
}
}
}
}
return classes.join(' ');
}

//CommonJS规范
if (typeof module !== 'undefined' && module.exports) {
module.exports = classNames;

//AMD规范
} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
// register as 'classnames', consistent with npm package name
define('classnames', [], function () {
return classNames;
});

//其他
} else {
window.classNames = classNames;
}
}());

代码真心短得可怜,而且还可以再DIY,最后三个if,其实你可以选择你项目用的规范来引入。默认支持 CommonJS规范/AMD规范/全局定义 三种。

我们再观察一下原理部分,看有没有什么bug。知己知彼才能放心插入

一个内部数组classes,然后对参数进行判断后将参数添加到内部数组里
参数类型判断条件

  • string或者number类型直接push到数组
  • Array类型则递归这个数组
  • Object类型则把键为true的加入数组

最后join了数组返回一个字符串。代码很简单,但是创意无限。
非常推荐大家用这个模块。有问题可以留言哈。


Copyright © 2015 - 2019 ManfredHu胡文峰的个人博客

All rights reserved. Designed and powered by ManfredHu.

粤ICP备18133029号