前言
- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第26期,链接:【若川视野 x 源码共读】第26期 | classnames - 掘金 (juejin.cn)。
classnames 是一个JavaScript工具库,用于 有条件地 将不同的class类名组合在一起
用法
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
// 多种不同类型的参数
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'
// 假值对应的类名都会被忽略
classNames(null, false, 'bar', undefined, 0, { baz: null }, ''); // => 'bar'
// 支持动态类名
let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true });
// 在React中的使用:将classNames赋值给元素的className属性即可
export default function App() {
return (
<div className={classNames(...)}></div>
)
}
源码解析
// 获取对象的hasOwnProperty方法,该方法用于判断某个属性是否是对象本身的,而不是继承自原型链
const hasOwn = {}.hasOwnProperty;
export default function classNames () {
let classes = '';
for (let i = 0; i < arguments.length; i++) {
const arg = arguments[i];
if (arg) {
classes = appendClass(classes, parseValue(arg));
}
}
return classes;
}
function parseValue (arg) {
// 如果是字符串,直接返回
if (typeof arg === 'string') {
return arg;
}
// 如果既不是字符串,也不是对象和数组,就返回空字符串
if (typeof arg !== 'object') {
return '';
}
// 如果是数组,调用classNames来返回一个组合好的结果字符串
if (Array.isArray(arg)) {
return classNames.apply(null, arg);
}
// arg.toString !== Object.prototype.toString 表示arg的toString方法不是继承自Object上
/**
* !arg.toString.toString().includes('[native code]')
* 如果arg有toString方法,进一步检查这个方法是否是原生的
* 方法是将 arg.toString 方法转换成字符串,然后检查它是否包含字符串 '[native code]'。如果一个函数的字符串表示中包含 '[native code]',这通常意味着函数是原生提供的,而不是用户定义的。
*/
if (arg.toString !== Object.prototype.toString && !arg.toString.toString().includes('[native code]')) {
return arg.toString();
}
let classes = '';
// 如果arg是对象
for (const key in arg) {
// hasOwn 判断key是否是arg对象本身的属性,而不是继承自原型链的属性
// arg[key] 判断key对应的值是否存在,且不为false
if (hasOwn.call(arg, key) && arg[key]) {
classes = appendClass(classes, key);
}
}
return classes;
}
function appendClass (value, newClass) {
if (!newClass) {
return value;
}
return value ? (value + ' ' + newClass) : newClass;
}
最后
读源码,相当于和大佬对话,给了我许多的收获。
如果对我的笔记感兴趣,也可以前往我的个人博客,里面有更多我的学习分享