Clsx + tailwind-merge

tailwind-merge 是一个自动合并 TailWindCSS 类的工具,合并之后可以自动删除重复的类,例如

import { twMerge } from 'tailwind-merge';
 
<button className={twMerge('text-red-300 px-4', className)}></button>

Button 上已经存在一个 px-4tailwind 类了,此时我们通过 className 传入一个新的类 px-2,那么 twMerge 会在合并的时候自动删除 px-4

使用 clsx 配合 tailwind-merge 创造一个 cn 工具函数,用来实现动态的 tailwind class:

import type { ClassValue } from 'clsx';
 
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
 
export function cn(...input: ClassValue[]) {
	return twMerge(clsx(input));
}

使用

<script>
	import { cn } from '../../../utils/tw';
 
	let isClick = false;
 
	function setClickState() {
		isClick = !isClick;
	}
</script>
 
<div>
	<div
		class={cn('text-red-400', {
			'text-blue-500': isClick
		})}
	>
		<h1>clsx + tailwind-merge</h1>
		<button on:click={setClickState}>onClick Change Color</button>
	</div>
</div>

Cva

使用 cva 实现 TailWindCSS 的扩展非常便于组件的封装,能够很简的通过 props 来控制元素的 class
通过 cva 定义一个组件:

<script lang="ts">
	import type { HTMLButtonAttributes } from 'svelte/elements';
	import { cva, type VariantProps } from 'cva';
 
	const button = cva({
		variants: {
			intent: {
				primary: 'bg-blue-600 text-white',
				secondary: 'bg-red-500 text-green'
			},
			size: {
				small: 'p-2',
				medium: 'p-6'
			}
		},
		compoundVariants: [{ intent: 'primary', size: 'medium', class: 'text-read-400' }]
	});
 
	interface $$Props extends HTMLButtonAttributes, VariantProps<typeof button> {}
 
	export let intent: $$Props['intent'] = 'primary';
	export let size: $$Props['size'] = 'medium';
</script>
 
<button {...$$props} class={button({ intent, size, class: $$props.class })}>
	<slot />
</button>

使用

<script>
	import CvaButton from './components/cva-button.svelte';
</script>
 
<div>
	<h1>cva</h1>
	<CvaButton>123</CvaButton>
	<CvaButton size="small" intent="secondary">123</CvaButton>
</div>
 

Cvabutton 会根据不同的属性展示不同的样式