使用cn()有什么好处?
cn()函数实际上就是将twMerge和clsx封装到了一起。
twMerge 有什么用?
twMerge 的产生是为了解决样式冲突问题。比如一个button组件,它本身自带color,我们在调用的时候又给它赋值一个color,那么这个color就会作为一个变量传入button组件的className,这个时候我们就有新旧两个color,这就是样式冲突。CSS 的层叠机制确实可以解决样式冲突,但它是在浏览器渲染阶段起作用的。而 twMerge 的价值在于提前优化,在代码层面减少冗余类名,提升可读性和可维护性。
// ❌ 不使用 twMerge
className={
"px-2 text-red-500",
"px-4 text-blue-500" // px-2 和 text-red-500 不会被正确覆盖
}
// 结果: "px-2 text-red-500 px-4 text-blue-500" (样式混乱)
// ✅ 使用 twMerge
import { twMerge } from "tailwind-merge"
className={twMerge(
"px-2 text-red-500",
"px-4 text-blue-500" // 会正确覆盖前面的值
)}
// 结果: "px-4 text-blue-500" (正确的样式)
// 使用 twMerge
className={twMerge(
"block sm:flex md:grid", // 基础样式
"sm:block md:flex" // 新的响应式样式会正确覆盖
)}
// 结果会正确处理响应式断点的优先级
className={twMerge(
"p-2 rounded-lg bg-blue-500",
isError && "bg-red-500 p-4", // 会正确覆盖 p-2 和 bg-blue-500
isLarge && "p-6" // 会正确覆盖之前的 padding
)}
clsx 有什么用?
clsx的主要作用就是"格式化",让类名更加美观可读。
//不使用clsx
className={
`px-4 py-2 rounded`,
isPrimary ? `bg-blue-500 text-white` : `bg-gray-200 text-gray-800`,
}
//使用clsx
className={clsx(`px-4 py-2 rounded`, {
"bg-blue-500 text-white": isPrimary,
"bg-gray-200 text-gray-800": !isPrimary,
}
可以通过例子看到,clsx可以将条件判断语句转化为条件对象语句。
除此之外clsx还支持:
// 支持嵌套数组
className={clsx(
'base',
['foo', 'bar'],
{ 'active': isActive },
[{ 'disabled': isDisabled }]
)}
不止这些
以上均为最重要的特性但cn()的功能不止这些,其中包括:
- 去除多余空格:
// 不使用 cn className={`base-class ${isActive ? 'active' : ''} ${isDisabled ? 'disabled' : ''}`} // 可能输出: "base-class "(多余的空格) // 使用 cn className={cn("base-class", isActive && "active", isDisabled && "disabled")} // 输出干净的结果: "base-class active disabled" - 处理falsy值
// 不使用 cn className={`base ${undefined} ${null} ${false}`} // 会产生 "base undefined null false" // 使用 cn className={cn("base", undefined, null, false)} // 只输出 "base"
如何使用cn()?
首先下载依赖npm install clsx tailwind-merge
然后自定义函数,我的存放位置:/src/lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
任何时候使用cn()吗?
从上面来看cn()无懈可击没有任何缺点,那我们需要任何情况都使用cn()吗?
当然不是,cn() 本质上是个处理函数,必然会对性能造成损耗,所以在简单场景我们无需使用cn()。
那推荐何时使用cn()?
推荐在组件上编写样式的时候使用,组件库:shadcn等、自己定义的组件。