前言
在寫react的時候動態寫入class比較繁瑣很囉嗦,記得有個模組可以來解決這個問題,於是乎找到了這個模組叫“classnames”,再者好奇這個模組的體積大小,然後對其進行了原始碼分析。
看看react如何動態新增class
如果不用第三方模組去實現動態新增class是這樣子的
const _classNames = window.people ? `active main` : `main`;
return (
<div className={_classNames}></div>
)
複製程式碼
這算比較簡單的了,如果條件夠多的時候是很可怕的, 想想就好了!!
使用classnames動態新增class
npm安裝
npm install classnames -S
複製程式碼
看!相比前面簡單明瞭,結構再複雜一樣能應付
const sidebarOpenClass = classNames({
main: true,
active: window.people
});
return (
<div className=${_classNames}></div>
)
複製程式碼
好吧。
分析classnames內部實現
程式碼並不多,刪掉空白行和註釋只有僅僅37行的程式碼,我將在程式碼裡以註釋的形式講解程式碼含義。
(function () {
`use strict`;
// => Object.hasOwnProperty 用於判斷某個成員是否在物件內
var hasOwn = {}.hasOwnProperty;
function classNames () {
// 儲存 className 值
var classes = [];
// 迴圈實參, arguments就是實際呼叫函式傳入的引數,類似陣列
for (var i = 0; i < arguments.length; i++) {
// 獲取實參value
var arg = arguments[i];
// 跳過false條件 => false, null, undefined, NaN, 空, ...
if (!arg) continue;
// 判斷傳入引數的型別
var argType = typeof arg;
// 如果引數的型別是 string 或者 number
if (argType === `string` || argType === `number`) {
// 直接追加到classes陣列後面
classes.push(arg);
// 如果引數是陣列並且長度大於0
} else if (Array.isArray(arg) && arg.length) {
// 呼叫自身函式,利用apply可以將陣列轉成字串
var inner = classNames.apply(null, arg);
// 現在是一個字串,隱士判斷布林值
if (inner) {
// 追加到陣列後面
classes.push(inner);
}
// 如果傳入的引數是物件
} else if (argType === `object`) {
// 對object進行遍歷
for (var key in arg) {
// 判斷key是否存在arg物件內並且key的值隱士轉換為true
if (hasOwn.call(arg, key) && arg[key]) {
// 將值追加到classes陣列後面
classes.push(key);
}
}
}
}
// 將陣列連線成字串以空格拼接 => a b c
return classes.join(` `);
}
// 如果是node.js環境執行
if (typeof module !== `undefined` && module.exports) {
classNames.default = classNames;
module.exports = classNames;
// 如果用的requirejs模組管理 AMD
} else if (typeof define === `function` && typeof define.amd === `object` && define.amd) {
define(`classnames`, [], function () {
return classNames;
});
// 否則執行於瀏覽器環境
} else {
window.classNames = classNames;
}
}());
複製程式碼
程式碼比較少,所以比較好分析。
classnames使用姿勢
classnames使用太靈活了,演示幾個demo
demox1
import classNames from `classnames`;
const _className = classNames(`foo`); // => `foo`
複製程式碼
demox2
const _className = classNames(`foo`, {
bar: true
});
// => `foo bar`
複製程式碼
demox3
const _className = classNames(`foo`, {
bar: true,
active: false,
}, [`arr-1`, `arr-2`]);
// => foo bar arr-1 arr-2
複製程式碼
classNames對實參是沒有限制的,看原始碼就明白了,比較常用的就是react專案當中。
總結
既然有了第三方外掛的存在,就沒必要重複造輪子了,練習和學習原始碼是提高技術的好機會,classnames編寫了單元測試,覆蓋率基本是100%,所以放心使用。