classnames的理解
本篇文章主要是学习classnames的相关理解及使用。
下面列举的是如何在项目中使用
安装方式
npm install classnames
使用方式
- 引入时可使用require的方式引入,也可以通过import的方式引入
使用方法
import classnames form 'classnames classnames('foo','bar') == 'foo bar' classnames('foo',{bar:true}) == 'foo bar'
一般在React中,我们会在构建组件或需要根据某些判断条件动态生成类名时,classnames
会非常有用。
示例一:
import React, { useState } from 'react'; export default function Button (props) { const [isPressed, setIsPressed] = useState(false); const [isHovered, setIsHovered] = useState(false); let btnClass = 'btn'; if (isPressed) btnClass += ' btn-pressed'; else if (isHovered) btnClass += ' btn-over'; return ( <button className={btnClass} onMouseDown={() => setIsPressed(true)} onMouseUp={() => setIsPressed(false)} onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > {props.label} </button> ); }
使用classnames
之后
import React, { useState } from 'react'; import classNames from 'classnames'; export default function Button (props) { const [isPressed, setIsPressed] = useState(false); const [isHovered, setIsHovered] = useState(false); const btnClass = classNames({ btn: true, 'btn-pressed': isPressed, 'btn-over': !isPressed && isHovered, }); return ( <button className={btnClass} onMouseDown={() => setIsPressed(true)} onMouseUp={() => setIsPressed(false)} onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > {props.label} </button> ); }
源码理解
classnames文件目录结构
classnames
┣ 📂benchmarks
┃ ┣ 📃fixtures.js
┃ ┣ 📃run.js
┃ ┣ 📃runChecks.js
┃ ┣ 📃runInBrowser.js
┃ ┣ 📃runSuite.js
┣ 📂tests
┃ ┣ 📃bind.js
┃ ┣ 📃dedupe.js
┃ ┣ 📃index.js
┣ 📃bind.js
┣ 📃dedupe.js
┗ 📃index.js
1. 基础功能
- index.js中代码并不多,在这个文件中定义了一个数组
classnames
,一个包含所有最终有效的class的数组
var classes = []
- for循环函数自带arguments实例,得到classnames函数的所有实参。当某个实参不存在时 跳过进入下一次迭代
for(var i = 0;i<arguments.lengthl;i++){ var arg = arguments[i]; if (!arg) continue; }
- 获得每个参数的数据类型,后面根据不同的数据类型做相应的处理;如果参数是字符串或数值,直接放到classes数组中;如果参数的数据类型是对象,处理方式如下
var argType = typeof arg; if (argType === 'string' || argType === 'number') { 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') { 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.push(key); } } }
- 提供了三种导出方式
if (typeof module !== 'undefined' && module.exports) { classNames.default = classNames; module.exports = classNames; } else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { // register as 'classnames', consistent with npm package name define('classnames', [], function () { return classNames; }); } else { window.classNames = classNames; }
2.bind
功能
在官方的文档中,bind版本给出的是在使用 css-modules
方式,或者抽象类和实际输出到DOM的真实类做映射的方式,可能需要使用bind变量
const classNames = require('classnames/bind'); const styles = { foo: 'abc', bar: 'def', baz: 'xyz', }; const cx = classNames.bind(styles); const className = cx('foo', ['bar'], { baz: true }); // => 'abc def xyz'
3. dedupe
功能
dedupe的主要功能是帮助消除类的重复数据,确保结果集中已经排除后面参数中指定的错误类。
相比于bind
功能,dedupe做的处理更多一些,
- 使用Object.create()创建一个新的对象,可以帮助后面跳过hasOwnProperty检查。
function StorageObject() {} StorageObject.prototype = Object.create(null);
- 利用对象的key不会重复的特点去重。
function _parseString (resultSet, str) { var array = str.split(SPACE); var length = array.length; for (var i = 0; i < length; ++i) { resultSet[array[i]] = true; } }
- 定义一个数组,遍历所有value值,将返回结果为true的放到list中
本文来自博客园,作者:前端加油站,转载请注明原文链接:https://www.cnblogs.com/bllx/p/17881041.html
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步