持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第10天,点击查看活动详情
本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
参考
作用
A simple JavaScript utility for conditionally joining classNames together.
一个简单的 JavaScript 实用程序,用于有条件地将类名连接在一起。
把对象数组等解析成字符串。bool为false的置为空字符串,对象属性是true的就加入,数组打平后判断。
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
源码
(function () {
'use strict';
var hasOwn = {}.hasOwnProperty;
// 通过数组收集 参数 ,对各种参数进行改造,后面用join拼起来
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);
// 如果是数组,递归加
//举个例子,function aa(a){if(Array.isArray(a)){return aa(...a) }else {return a}} [['a']]=>'a'
} else if (Array.isArray(arg)) {
if (arg.length) {
var inner = classNames.apply(null, arg);
if (inner) {
classes.push(inner);
}
}
} else if (argType === 'object') {
//如是对象,判断对象的toString方法有没有改过,正常的话
if (arg.toString === Object.prototype.toString) {
//遍历属性,对象hasOwnProperty方法判断是否是对象属性而非原型上的且值为真,加入
for (var key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes.push(key);
}
}
} else {
classes.push(arg.toString());
}
}
}
return classes.join(' ');
}
//兼容导出环境,node
if (typeof module !== 'undefined' && module.exports) {
classNames.default = classNames;
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;
}
//但是没看到怎么兼容esm的,没有export xx呀。。
}());
逻辑:
1.创个数组
2.遍历参数,假值跳过,数字或字符直接加,对象遍历且值为真就加,数组递归且值为真就加
3.数组join成字符串
Alternate dedupe version
classNames('foo', { foo: false, bar: true }); // => 'bar'
重复数据可以覆盖删除,主要是下面的代码,对象值为false也存resultSet数组里,最后遍历数组为true的值再join。
function _parseObject (resultSet, object) {
if (object.toString === Object.prototype.toString) {
for (var k in object) {
if (hasOwn.call(object, k)) {
resultSet[k] = !!object[k];
}
}
} else {
resultSet[object.toString()] = true;
}
}
Alternate bind version
映射,取对象值不取属性
var classNames = require('classnames/bind');
var styles = {
foo: 'abc',
bar: 'def',
baz: 'xyz'
};
var cx = classNames.bind(styles);
var className = cx('foo', ['bar'], { baz: true }); // => "abc def xyz"
//映射,取对象值不取属性
//源码
function classNames () {
var classes = [];
for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (!arg) continue;
var argType = typeof arg;
//bind指定了this为 styles ,那么在原先基础 classes.push(arg); 改成 classes.push( this[arg] );
if (argType === 'string' || argType === 'number') {
classes.push(this && this[arg] || arg);
} else if (Array.isArray(arg)) {
classes.push(classNames.apply(this, arg));
} else if (argType === 'object') {
if (arg.toString === Object.prototype.toString) {
for (var key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes.push(this && this[key] || key);
}
}
} else {
classes.push(arg.toString());
}
}
}
return classes.join(' ');
}