在好久以前若是一个组件/元素有不少个状态/属性的时候,一般须要动态的设置多个样式类;好比下面的一个checkbox组件;它拥有size属性,disabled和checked状态。咱们常常的作法是以下:git
render () { let { title = "", disabled = false, children, style, size } = this.props; let { checked } = this.state; return <label style={style} className={"el-checkbox-button" + (size ? ' el-checkbox-button--' + size : '') + (disabled ? ' is-disabled' : "") + (checked ? ' is-checked' : "") }> ... </label>; }
这样的作法有二个问题:github
classnames的出现帮咱们解决了上面的问题;下面我用classnames改写一下上面的代码。
代码以下:数组
render () { let { title = "", disabled = false, children, style, size } = this.props; let { checked } = this.state; return <label style={style} className={classnames('el-checkbox-button--' + size, { 'is-disabled': disabled, 'is-checked': checked )}> .... </label>; }
github地址:https://github.com/JedWatson/...;
核心源码大概30行,下面咱们结合源码看一下它是怎么实现的。app
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; if (argType === 'string' || argType === 'number') { classes.push(arg); } else if (Array.isArray(arg) && arg.length) { var inner = classNames.apply(null, arg); if (inner) { classes.push(inner); } } else if (argType === 'object') { for (var key in arg) { if (hasOwn.call(arg, key) && arg[key]) { classes.push(key); } } } } return classes.join(' '); }
梳理一下整个流程:函数
{'is-disabled': disabled}
则遍历对象,若是arg[key]为true,则push进classes数组代码十分简洁优雅。源码分析
从源码来看,classNames能够接入的参数是多种多样的,下面列举一些。this
//字符串(能够单个,多个字符串) classNames('el-checkbox-button--m', "is-disabled"); //对象(能够单个,多个) classNames({"is-disabled":true}, {'is-disabled': disabled}); //字符串+对象 classNames('el-checkbox-button--m', {"is-disabled":true, 'is-disabled': disabled}); //数组(数组项能够是字符串,对象) classNames(['el-checkbox-button--m', "is-disabled"]); classNames(['el-checkbox-button--m', {"is-disabled":true,'is-disabled': disabled}]);
好了,因为源码比较简单,就不在废话了。code