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