在好久以前若是一個組件/元素有不少個狀態/屬性的時候,一般須要動態的設置多個樣式類;好比下面的一個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