我正在参加会员专属活动-源码共读第一期,点击参加
前语
本期的源码阅览使命是:
- 学会 classnames 的用法
- 学会 classnames 的原理
- 测验用例的运用
资源:
- 文章地址:源码共读第一期|classnames
- 源码地址:JedWatson/classnames: A simple javascript utility for conditionally joining classNames together (github.com)
classnames 的用法
Classname 是一个 JavaScript 库,它答应您有条件地将类名连接在一起。在构建 React 组件或需求依据某些条件动态生成类名时,它可能十分有用。
下面是一个怎么运用 classnames
的比如:
import classnames from 'classnames';
const Button = ({ primary, size }) => {
const classes = classnames('btn', {
'btn-primary': primary,
'btn-large': size === 'large',
'btn-small': size === 'small',
});
return <button className={classes}>Click me</button>;
};
在上面的示例中,classnames
函数接受一个类名和一个将类名映射为布尔值的目标。假如给定类名的布尔值为 true,则该类名将包括在类名的终究列表中。假如值为 false,则不包括类名。
还能够将一个字符串作为第二个参数传递给类名,在这种情况下,假如值为 true,那么它将被添加到类名的终究列表中。
const classes = classnames('btn', primary && 'btn-primary');
学会 classnames 的原理
classnames 源码并不复杂,除去一些兼容性判别,主要功能完成的代码如下:
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)) {
if (arg.length) {
var inner = classNames.apply(null, arg);
if (inner) {
classes.push(inner);
}
}
} else if (argType === "object") {
if (
arg.toString !== Object.prototype.toString &&
!arg.toString.toString().includes("[native code]")
) {
classes.push(arg.toString());
continue;
}
for (var key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes.push(key);
}
}
}
}
return classes.join(" ");
}
主要作业原理如下:
- 函数声明晰一个名为
class
的空数组,该数组将用于存储生成的类名。 - 然后,函数进入一个循环,循环遍历传递给函数的参数。关于每个参数,履行以下步骤:
- 查看参数的类型。假如它是一个字符串或数字,添加到类数组。
- 假如参数是数组,则函数查看它是否为非空。假如是,则函数以数组元素作为参数递归地调用自身,并将成果添加到类数组中。
- 假如参数是一个目标,那么函数将查看它是否有一个
toString
办法,该办法不是本机Object.Prototype.toString
办法。假如是这样,调用oString
的成果将添加到类数组中。假如不是,函数将遍历目标自己的可枚举特点,并将特点称号添加到类数组中(假如它们的对应值为真)。 - 循环结束后,将类数组合并到一个单独的字符串中,运用一个空格字符作为分隔符,并回来成果字符串。
测验用例的运用
className
库运用 Mocha
进行代码测验:
Mocha
是一个运转在 Node.js 和浏览器上的 JavaScript 测验结构。它用于编写和运转 JavaScript 代码的测验用例。
运用 Mocha
写测验用例的简略示例:
const assert = require("assert");
describe("myFunction", () => {
it("should return the expected result", () => {
assert.equal(myFunction(1, 2), 3);
});
});
- it 函数用于界说单个测验用例。
- 断言模块用于验证函数是否回来预期的成果。
一些测验用例
describe('classNames', function () {
// 测验能够识别具有真值得目标
it('keeps object keys with truthy values', function () {
assert.equal(classNames({
a: true,
b: false,
c: 0,
d: null,
e: undefined,
f: 1
}), 'a f');
});
// 查看 classNames 函数是否正确地处理了其输入参数中的假值,而且只在生成的类名字符串中包括真值。
it('joins arrays of class names and ignore falsy values', function () {
assert.equal(classNames('a', 0, null, undefined, true, 1, 'b'), 'a 1 b');
});
// 这个测验用例查看 classNames 函数是否正确地处理了各种不同类型的参数
it('supports heterogenous arguments', function () {
assert.equal(classNames({a: true}, 'b', 0), 'a b');
});
// 这个测验用例查看 classNames 函数是否正确地从生成的类名字符串中删除了前导空格和尾随空格。
it('should be trimmed', function () {
assert.equal(classNames('', 'b', {}, ''), 'b');
});
// 这个测验用例查看 classNames 函数在调用时是否回来一个空字符串,该函数的仅有参数是一个空目标。
it('returns an empty string for an empty configuration', function () {
assert.equal(classNames({}), '');
});
// ... 省掉部分测验用例
});
总结
Classname 十分有用,它能够依据应用程序的状况构建动态类名。避免编写冗长和重复的 if-else 语句来构建类名。同时,源码测验用例写得十分详尽,很有学习意义,能够用来参考给自己的代码写一些测验用例。