前言
这里我引用源码文档中的一句话来作为开场白: A simple JavaScript utility for conditionally joining classNames together.
话不多说,咱们直接开始 classnames 的源码学习。
核心源码解读
直接来看它的源码部分,以下这是 classnames 的核心源码,核心源码不过才四十几行,让我们一步步解读一下都是什么意思吧。
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) && arg.length) {var inner = classNames.apply(null, arg);if (inner) {classes.push(inner);}} else if (argType === 'object') {for (var key in arg) {if (hasOwn.call(arg, key) && arg[key]) {classes.push(key);}}}}return classes.join(' ');}
这里的 hasOwnProperty 这个方法是用来判断对象的属性是否属于自己本身。
整个源码里做了三个 if 类型判断。首先定义 classes 存储数组,然后遍历 arguments 拿到所有的参数;如果该项的值为 undefined、null 之类的就直接跳过;通过 var argType = typeof arg
获取该项的类型,然后 push 到 classes 中就可以了。
这里面对我而言比较难懂的是这段代码:
else if (Array.isArray(arg) && arg.length) {var inner = classNames.apply(null, arg);if (inner) {classes.push(inner);}
查阅资料得知这里利用 递归+apply 达到数组扁平化的效果,说的简单点就是将数组分拆成参数传入 classNames 函数中。
最后 return 用 join 方法将数组变为字符串,用空格隔开。
这里介绍一下参数类型的判断:
- 如果是 string 或者 number,直接 push 进 classes 中
- 如果是数组,则通过
classNames.apply(null, arg)
,将数组分拆成参数传给 classNames 函数进行递归 - 如果是对象,遍历对象,如果 arg[key] 为真,则 push 进 classes 数组
classnames 运用
在 react 项目中,经常使用到 className。使用如下:
<div className="box1"></div>
.box1{color:blue;
}
但是缺点也很明显,如果想动态添加类名,className 就有点吃力了。因此这时候就需要 classnames 了。使用 npm install classnames
安装。
众所周知,classnames 是一个库函数,使用方法有很多种,下面介绍一种比较常用的写法。
import classnames from 'classnames';
<div className={classnames({box1:true , box2: false},'box3')}></div>
// 用 className 方式表示如下
<div className="box1 box3"></div>
总结
总体来说,通过阅读源码学到了 arguments 和 apply 的应用,了解了这个经常使用的库的源码可以更好地理解 classnames 的作用。
从文档中熟悉了 classnames 的用法,从 github 上了解了 classnames 的源码,这是一个与 react 项目紧密结合的库函数,所以多看文档多看源码多学习。
最后
为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。
有需要的小伙伴,可以点击下方卡片领取,无偿分享