classnames 是公司项目中使用较频繁的一个库,因为能方便动态切换 class 名称。
放下对比大家感受下~
<!-- before -->
let clsName = 'conetnt'
if (showContent) {
clsName += ' show'
} else {
clsName += ' hide'
}
if (needMargin) clsName += ' add-margin'
return <div className={clsName} />
<!-- 使用 classnames 后 -->
return <div className={classnames('content', { show: showContent, hide: !showContent, 'add-margin': needMargin })} />
又比如自己封装的业务组件,调用方经常需要传入自定义 class 类名,使用 classnames
的话是这个样子:
// 假设 clsName 为父组件传入的自定义类名,可选
<div className={classnames('self-classname', { [clsName]: !!clsName })} />
以上 classnames 可以根据 truly 值动态选择拼接 class 名称,在前端开发中是很方便的。
使用多了逐渐对 classnames
产生了好奇:它的内部是如何运行的?🤔
github 上查看源码后也从中学到了一些东西 👍 ,分享给大家:
// 保存 object 的 hasOwnProperty 方法引用
var hasOwn = {}.hasOwnProperty
function classNames() {
var classes = []
for (var i = 0; i < arguments.length; i ++) {
var arg = arguments[i]
// 跳过 falsy 参数值
if (!arg) continue
var argType = typeof arg
if (argType === 'string' || argType === 'number') {
// 如果某个参数是 string 或 number 类型,直接放入 classes 数组
classes.push(arg)
} else if (Array.isArray(arg) && arg.length) {
// 若某个参数是 数组 类型,将数组里的参数传入 classNames 再调用一次并获取返回值
var inner = classNames.apply(null, arg)
if (inner) classes.push(inner)
} else if (argType === 'object') {
if (arg.toString !== Object.prototype.toString) {
// 若某元素有自定义 toString 方法,调用该方法并将返回值存入 classes
classes.push(arg.toString())
} else {
for (var key in arg) {
// 若某元素为对象,遍历该对象的 key,只取元素自身不为 falsy 的 key 放入 classes
if (hasOwn.call(arg, key) && arg[key]) classes.push(key)
}
}
}
}
// 将 classes 元素通过 ' ' 空格拼接后返回,即拼接后的 class 名称
return classes.join(' ')
}
方法测试截图:
了解源码内部运行机制,能让我们在使用的时候明确结果是如何产生的,同时哪些使用方法是不适合的等等~ 🤗
– End –