一个生成类名的工具-classnames

90 阅读3分钟

「我正在参与掘金会员专属活动-源码共读第一期,点击参与

本篇文章介绍的是classnames,一个简单的JavaScript工具,作用是将classnames聚集在一起。

安装

# via npm
npm install classnames

# via Bower
bower install classnames

# or Yarn 
yarn add classnames

使用

var classNames = require('classnames');
classNames('foo', 'bar'); // => 'foo bar'

还可以直接将index.jsdedupe.js后续提到的去重版本)通过script标签引入到页面,全局有个classNames方法可以调用。如果你使用的是RequireJS,定义一下模块。

classNames方法会处理若干个字符串类型或者对象参数,foo{foo: true}的简写,如果参数的值是falsy,最终输出不会包含该值。

classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': false }); // => ''

// 其他的falsy值会被忽略的情况
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'

数组会按照以上规则递归扁平化处理

var arr = ['b', { c: true, d: false }];
classNames('a', arr); // => 'a b c'

ES6中的计算属性

let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true }); // => 'btn-primary'

当然还有备用的去重版本

var classNames = require('classnames/dedupe');

classNames('foo', 'foo', 'bar'); // => 'foo bar'
classNames('foo', { foo: false, bar: true }); // => 'bar'

使用css-modules用的版本,根据传入的classNames得到对应的值。平时没有使用css-modules,所以在这里就不展开了。

当然还能在React.js里使用

var classNames = require('classnames');

class Button extends React.Component {
  // ...
  render () {
    var btnClass = classNames({
      btn: true,
      'btn-pressed': this.state.isPressed,
      'btn-over': !this.state.isPressed && this.state.isHovered
    });
    return <button className={btnClass}>{this.props.label}</button>;
  }
}

看到这里,Vue的小伙伴会不会联想到在Vue.js里使用的:class动态绑定类名。

<div :class={isActive ? 'active': ''}></div>

这句代码的意思是: 如果isActive为真类名就是active,否则为空字符串。和classNames函数是不是有异曲同工之妙。

Polyfill:Array.isArray兼容老版本的浏览器垫片

源码

了解一个项目的最直接简单的方式就是看package.json

"main": "index.js"

通过这个配置项找到源码入口。

首先定义了在代码13行定义了classNames函数,48行开始做了各个模块的兼容处理。 核心看classNames函数

  1. 声明classes数组用来存储结果
  2. 遍历了arguments内置参数。如果为假值直接跳过
  3. 得到每个参数的类型,如果是字符串类型或数字类型,直接添加到classes
  4. 如果参数是数组,做递归处理classNames.apply(null, arg)自调用
  5. 如果参数是对象:考虑toString()是否是自定义的如果是的将toString()结果添加到classess里(这里为了避免循环的情况考虑toString直接使用toString),否则,遍历对象将对象的自有属性加入classes里。
  6. 最后将数组元素通过空格拼接

结束语

整个源码还是很通俗易懂,在我们阅读的时候其实还是很轻松的,如果我们自己来实现的话,还是一个很困难的事情的。代码呈现在我们面前,就很顺利的跟着作者的思路走下来,如果自己实现就会出现磕磕绊绊,所以呢,多学习源码还提高代码的素质很有必要的。