【React】classnames 优化类名控制

1. 介绍

classnames是一个简单的JS库,可以非常方便的通过条件动态的控制class类名的显示

ClassNames是一个用于有条件处理classname字符串连接的库

简单来说就是动态地去操作类名,把符合条件的类名粘在一起

现在的问题:字符串的拼接方式不够直观,也容易出错

2. 安装

javascript 复制代码
npm install classnames

3. 引入

在nodejs里引入

javascript 复制代码
var classNames = require('classnames');

在js里引入

javascript 复制代码
import classnames from 'classnames'

基本使用

普通字符串粘合

将参数拼接为字符串,中间用空格分开

javascript 复制代码
classNames('foo', 'bar'); // => 'foo bar'

带条件的类参数

这里第二个参数是对象类型,键值为true,则粘合进classname里

javascript 复制代码
classNames('foo', { bar: true }); // => 'foo bar'

若为false,则不粘进去

javascript 复制代码
classNames('foo', { bar: false }); // => 'foo'

参数类型是数组

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

特别注意

null和undefiend会被忽略

javascript 复制代码
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'

在react中优雅地使用classnames

下面这段代码,通过if-else判断state的状态,动态选择btnClass的具体值

javascript 复制代码
class Button extends React.Component {
  // ...
  render () {
    var btnClass = 'btn';
    if (this.state.isPressed) btnClass += ' btn-pressed';
    else if (this.state.isHovered) btnClass += ' btn-over';
    return <button className={btnClass}>{this.props.label}</button>;
  }
}

现在用classnames来做,btnClass就可以边成一个对象,通过键值的条件确定最终生成的classname

javascript 复制代码
import classnames from '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>;
  }
}

我的使用

javascript 复制代码
import classnames from 'classnames'

 <li className="nav-sort">
            {/* 高亮类名: active */}
            {tabsList.map((item,index)=>
            <span className={classnames('nav-item',{active:item.type===type})}
            key={index} onClick={()=>{changTab(item.type)}} >{item.text}</span>)}
            {/* {tabsList.map((item,index)=>
            <span className={`nav-item ${item.type===type && 'active'}`} 
            key={index} onClick={()=>{changTab(item.type)}} >{item.text}</span>)} */}
          </li>

原理

classNames源码:

javascript 复制代码
function classNames() {
  var classes = [];//用于存储生成的类名

  for (var i = 0; i < arguments.length; i++) {//遍历classnames的所有参数
    var arg = arguments[i];
    if (!arg) continue;

    var argType = typeof arg; //拿到每一个参数的类型

    if (argType === "string" || argType === "number") { //如果是字符串或数字就直接加到classes数组里
      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") { //如果是对象且有自定义的toString方法,则调用toString方法添加到classes对象里,if里面的表达式下面会详细介绍
      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数组里
          classes.push(key);
        }
      }
    }
  }

  return classes.join(" ");// 最后在中间加上空格转成字符串
}

arg.toString !== Object.prototype.toString啥意思?

我们知道所有js对象都继承Object对象,即都继承toString方法,这个表达式的意思就是这个对象的toString方法不是继承自Object.prototype

arg.toString.toString().includes("native code") 啥意思?

我们首先要知道toString方法的一些知识:当我们对一个自定义函数调用toString()方法时,可以得到该函数的源代码;如果对内置函数使用toString()方法时,会得到一个'native code'字符串。因此,可以使用toString()方法来区分自定义函数和内置函数,注意是对函数调用toString()方法,所以我们通过对toString函数调用toString方法,就能得知这个toString是内置的,还是自定义的

这里两个表达式连起来的意思就是:现在这个类有toString方法,而且还是自定义的

  References

相关推荐
一木 之林4 小时前
Agent智能体学习总结:从一次调用到模型自主规划、工具调用与 ReAct 循环的项目实战-6/6
前端·人工智能·学习·react.js
程序员Sunday4 小时前
React 的 useEffect 怎么工作?依赖数组、清理函数和重复执行如何理解?
前端·javascript
程序员Sunday4 小时前
Vue 3 响应式原理是什么?Proxy、ref 和 reactive 有什么区别?
前端·javascript
mldong5 小时前
一个 npm 包,九页审批中心:Vue3 项目接上工作流引擎
前端·javascript·vue.js
刘发财15 小时前
前端如何生成10000页PDF文件?
前端·javascript·开源
A接拉起00716 小时前
2026 年 JavaScript 开发者需要了解的知识
前端·javascript·后端
_馒头16 小时前
pixiJs游戏开发实践 - 跳棋小游戏
javascript·vue.js
三*一16 小时前
优化修整算法
前端·javascript·算法
楠楠子呀17 小时前
英语、西语、阿语客户各开一个口:多语言获客的分流方案
开发语言·javascript·ecmascript·跨境电商·whatsapp·营销工具
半个落月18 小时前
LangGraph.js 实战:从状态图到分支、循环、检查点与人工中断
javascript·人工智能·langchain