小白也能看懂的 classNames 源码解读

225 阅读1分钟

classNames 的用法

支持的参数类型

export type Value = string | number | boolean | undefined | null;
export type Mapping = Record<string, unknown>;
export interface ArgumentArray extends Array<Argument> {}
export type Argument = Value | Mapping | ArgumentArray;
classNames('a', 0, null, undefined, true, 1, 'b')   // => 'a 1 b'
classNames({a: true}, 'b', 0)  // => 'a b'
classNames(['a', 'b'])   // => 'a b'
  • 为了能绑定 css-module 的样式表的动态 class names
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"

支持自定义 toString()

classNames({
    toString: function () { return 'classFromMethod'; }
})  
//  =>'classFromMethod'

解读源码思想

  • 动态类型的参数解析
    • 动态参数使用 arguments,遍历 arguments 取出参数
    • 判断参数类型 typeof , Array.isArray
  • 如果是数组类型,用 classNames.apply 递归,直到解析到原始值类型string||number image.png
  • 如果是对象,使用 for...in 遍历对象,会把对象自身的和继承的可枚举的属性遍历出来,所以还要用hasOwnProperty来判断是不是自身的属性

image.png

  • bind 的用法

image.png