- 本文参加了由公众号@若川视野 发起的每周源码共读活动, 点击了解详情一起参与。
- 这是源码共读的第26期,链接
classnames
概念
- 组合
classNames
,A simple JavaScript utility for conditionally joining classNames together.
Usage
# via npm
npm install classnames
# via Bower
bower install classnames
# or Yarn (note that it will automatically save the package to your `dependencies` in `package.json`)
yarn add classnames
var classNames = require('classnames');
classNames('foo', 'bar'); // => 'foo bar'
源码解析
-
参数取值
arguments
并遍历 -
判断每个参数的有效性,无效则跳过
-
取值参数类型,并判断
-
类型如果是
string
number
则直接push
-
类型如果是
Array
且有效,则递归调用classNames
-
类型如果是
Object
,判断是否覆盖了toString
方法,未覆盖 则遍历 key,且判断 key 值有效性,如果覆盖 则直接调用toString
-
最后返回空格间隔的字符串
classes.join(' ')
(function() {
"use strict";
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;
// 类型判断 string 和 number 直接 push
if (argType === "string" || argType === "number") {
classes.push(arg);
} 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) {
// 未覆盖 则取遍历 key,且判断key值有效性
for (var key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes.push(key);
}
}
} else {
// 如果覆盖 则直接调用
classes.push(arg.toString());
}
}
}
return classes.join(" ");
}
if (typeof module !== "undefined" && module.exports) {
classNames.default = classNames;
module.exports = classNames;
} 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;
}
})();
收获
-
了解
arg.toString === Object.prototype.toString
-
各种使用方法可参考测试用例,基本都能覆盖到 tests index