|
@@ -2,4 +2,489 @@
|
|
|
description: "小程序ui开发指令"
|
|
description: "小程序ui开发指令"
|
|
|
---
|
|
---
|
|
|
|
|
|
|
|
-按小程序ui规范,小程序表单开发规范
|
|
|
|
|
|
|
+按小程序ui规范,小程序表单开发规范(.roo/commands/mini-form.md)
|
|
|
|
|
+
|
|
|
|
|
+# 小程序UI开发规范 (Tailwind CSS v4)
|
|
|
|
|
+
|
|
|
|
|
+## 概述
|
|
|
|
|
+
|
|
|
|
|
+本规范定义了基于Taro框架的小程序UI开发标准,采用Tailwind CSS v4原子化样式和Heroicons图标库,遵循shadcn/ui组件设计模式。
|
|
|
|
|
+
|
|
|
|
|
+## 技术栈
|
|
|
|
|
+
|
|
|
|
|
+- **Taro 4** - 跨端小程序框架
|
|
|
|
|
+- **React 18** - 前端框架
|
|
|
|
|
+- **Tailwind CSS v4** - 原子化CSS框架
|
|
|
|
|
+- **@egoist/tailwindcss-icons** - 图标库集成
|
|
|
|
|
+- **@weapp-tailwindcss/merge** - Tailwind类名合并工具(小程序版tailwind-merge)
|
|
|
|
|
+- **clsx** - 条件样式类名管理
|
|
|
|
|
+
|
|
|
|
|
+## 目录结构
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+mini/
|
|
|
|
|
+├── src/
|
|
|
|
|
+│ ├── components/
|
|
|
|
|
+│ │ └── ui/ # UI组件库
|
|
|
|
|
+│ │ ├── button.tsx
|
|
|
|
|
+│ │ ├── input.tsx
|
|
|
|
|
+│ │ ├── card.tsx
|
|
|
|
|
+│ │ └── ...
|
|
|
|
|
+│ ├── pages/
|
|
|
|
|
+│ ├── utils/
|
|
|
|
|
+│ └── app.css # Tailwind样式入口
|
|
|
|
|
+├── tailwind.config.js # Tailwind配置
|
|
|
|
|
+└── postcss.config.js # PostCSS配置
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 样式规范
|
|
|
|
|
+
|
|
|
|
|
+### 1. Tailwind CSS v4 使用规范
|
|
|
|
|
+
|
|
|
|
|
+#### 1.1 基础类名使用
|
|
|
|
|
+```typescript
|
|
|
|
|
+// ✅ 正确使用原子类
|
|
|
|
|
+<View className="flex items-center justify-between p-4 bg-white rounded-lg shadow-sm">
|
|
|
|
|
+ <Text className="text-lg font-semibold text-gray-900">标题</Text>
|
|
|
|
|
+</View>
|
|
|
|
|
+
|
|
|
|
|
+// ❌ 避免使用内联样式
|
|
|
|
|
+<View style={{ display: 'flex', alignItems: 'center', padding: 16 }}>
|
|
|
|
|
+ <Text style={{ fontSize: 18, fontWeight: '600' }}>标题</Text>
|
|
|
|
|
+</View>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 1.2 类名合并规范
|
|
|
|
|
+```typescript
|
|
|
|
|
+// ✅ 使用twMerge处理动态类名冲突
|
|
|
|
|
+import { twMerge } from '@weapp-tailwindcss/merge'
|
|
|
|
|
+
|
|
|
|
|
+// 处理静态和动态类名的冲突
|
|
|
|
|
+<View className={twMerge('px-4 py-2', isActive ? 'bg-blue-500' : 'bg-gray-200')}>
|
|
|
|
|
+ <Text>按钮</Text>
|
|
|
|
|
+</View>
|
|
|
|
|
+
|
|
|
|
|
+// 处理多个条件类名的合并
|
|
|
|
|
+<View className={twMerge(
|
|
|
|
|
+ 'flex items-center',
|
|
|
|
|
+ isActive && 'bg-blue-500 text-white',
|
|
|
|
|
+ isDisabled && 'opacity-50 cursor-not-allowed',
|
|
|
|
|
+ customClassName
|
|
|
|
|
+)}>
|
|
|
|
|
+ <Text>复杂组件</Text>
|
|
|
|
|
+</View>
|
|
|
|
|
+
|
|
|
|
|
+// ❌ 避免手动拼接类名导致冲突
|
|
|
|
|
+<View className={`px-4 py-2 ${isActive ? 'bg-blue-500' : 'bg-gray-200'} ${customClassName}`}>
|
|
|
|
|
+ <Text>按钮</Text>
|
|
|
|
|
+</View>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 1.2 响应式设计
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 使用Tailwind的响应式前缀
|
|
|
|
|
+<View className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
|
|
|
+ <View className="w-full sm:w-1/2 md:w-1/3" />
|
|
|
|
|
+</View>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 1.3 状态样式
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 悬停和焦点状态
|
|
|
|
|
+<Button className="bg-blue-500 hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
|
|
|
|
+ 点击按钮
|
|
|
|
|
+</Button>
|
|
|
|
|
+
|
|
|
|
|
+// 禁用状态
|
|
|
|
|
+<Button className="disabled:opacity-50 disabled:cursor-not-allowed">
|
|
|
|
|
+ 禁用按钮
|
|
|
|
|
+</Button>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 2. 图标使用规范
|
|
|
|
|
+
|
|
|
|
|
+#### 2.1 图标
|
|
|
|
|
+使用`@egoist/tailwindcss-icons`提供的图标类名:
|
|
|
|
|
+"mdi", "lucide", "heroicons", "heroicons-outline", "heroicons-solid"
|
|
|
|
|
+
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 基础用法
|
|
|
|
|
+<View className="i-heroicons-user-20-solid text-gray-600" />
|
|
|
|
|
+<Button className="flex items-center gap-2">
|
|
|
|
|
+ <View className="i-heroicons-plus-20-solid" />
|
|
|
|
|
+ <Text>添加</Text>
|
|
|
|
|
+</Button>
|
|
|
|
|
+
|
|
|
|
|
+// 图标大小和颜色
|
|
|
|
|
+<View className="i-heroicons-home-16-solid w-6 h-6 text-blue-500" />
|
|
|
|
|
+<View className="i-heroicons-cog-8-tooth-20-solid w-8 h-8 text-gray-400" />
|
|
|
|
|
+
|
|
|
|
|
+// 图标变体
|
|
|
|
|
+// solid - 实心图标
|
|
|
|
|
+// outline - 轮廓图标
|
|
|
|
|
+// mini - 迷你图标 (20x20)
|
|
|
|
|
+// micro - 微型图标 (16x16)
|
|
|
|
|
+<View className="i-heroicons-heart-20-solid text-red-500" />
|
|
|
|
|
+<View className="i-heroicons-heart-20-outline text-red-500" />
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 2.2 图标命名规则
|
|
|
|
|
+```
|
|
|
|
|
+i-heroicons-[图标名]-[大小]-[变体]
|
|
|
|
|
+```
|
|
|
|
|
+- 大小: 16 | 20 | 24
|
|
|
|
|
+- 变体: solid | outline
|
|
|
|
|
+
|
|
|
|
|
+### 3. UI组件规范
|
|
|
|
|
+
|
|
|
|
|
+#### 3.1 组件文件结构
|
|
|
|
|
+每个UI组件应包含:
|
|
|
|
|
+```typescript
|
|
|
|
|
+// mini/src/components/ui/button.tsx
|
|
|
|
|
+import { Button as TaroButton, ButtonProps } from '@tarojs/components'
|
|
|
|
|
+import { cn } from '@/utils/cn'
|
|
|
|
|
+import { cva, type VariantProps } from 'class-variance-authority'
|
|
|
|
|
+
|
|
|
|
|
+const buttonVariants = cva(
|
|
|
|
|
+ 'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background',
|
|
|
|
|
+ {
|
|
|
|
|
+ variants: {
|
|
|
|
|
+ variant: {
|
|
|
|
|
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
|
|
|
+ destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
|
|
|
|
+ outline: 'border border-input hover:bg-accent hover:text-accent-foreground',
|
|
|
|
|
+ secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
|
|
|
+ ghost: 'hover:bg-accent hover:text-accent-foreground',
|
|
|
|
|
+ link: 'underline-offset-4 hover:underline text-primary',
|
|
|
|
|
+ },
|
|
|
|
|
+ size: {
|
|
|
|
|
+ default: 'h-10 py-2 px-4',
|
|
|
|
|
+ sm: 'h-9 px-3 rounded-md',
|
|
|
|
|
+ lg: 'h-11 px-8 rounded-md',
|
|
|
|
|
+ icon: 'h-10 w-10',
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ defaultVariants: {
|
|
|
|
|
+ variant: 'default',
|
|
|
|
|
+ size: 'default',
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+interface ButtonProps extends ButtonProps, VariantProps<typeof buttonVariants> {}
|
|
|
|
|
+
|
|
|
|
|
+export function Button({ className, variant, size, ...props }: ButtonProps) {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <TaroButton
|
|
|
|
|
+ className={cn(buttonVariants({ variant, size, className }))}
|
|
|
|
|
+ {...props}
|
|
|
|
|
+ />
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 3.2 常用组件示例
|
|
|
|
|
+
|
|
|
|
|
+**按钮组件 (Button)**
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 使用示例
|
|
|
|
|
+<Button variant="primary" size="lg" onClick={handleClick}>
|
|
|
|
|
+ <View className="i-heroicons-plus-20-solid mr-2" />
|
|
|
|
|
+ 创建用户
|
|
|
|
|
+</Button>
|
|
|
|
|
+
|
|
|
|
|
+<Button variant="outline" size="sm" disabled={loading}>
|
|
|
|
|
+ {loading && <View className="i-heroicons-arrow-path-20-solid animate-spin mr-2" />}
|
|
|
|
|
+ 加载中...
|
|
|
|
|
+</Button>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**卡片组件 (Card)**
|
|
|
|
|
+```typescript
|
|
|
|
|
+<Card className="p-6 bg-white rounded-lg shadow-sm">
|
|
|
|
|
+ <CardHeader>
|
|
|
|
|
+ <View className="flex items-center justify-between">
|
|
|
|
|
+ <Text className="text-lg font-semibold">用户信息</Text>
|
|
|
|
|
+ <View className="i-heroicons-user-circle-20-solid text-gray-400" />
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </CardHeader>
|
|
|
|
|
+ <CardContent>
|
|
|
|
|
+ <Text className="text-gray-600">用户详情内容</Text>
|
|
|
|
|
+ </CardContent>
|
|
|
|
|
+</Card>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**输入框组件 (Input)**
|
|
|
|
|
+```typescript
|
|
|
|
|
+<View className="space-y-2">
|
|
|
|
|
+ <Label htmlFor="username">用户名</Label>
|
|
|
|
|
+ <View className="relative">
|
|
|
|
|
+ <View className="absolute left-3 top-1/2 -translate-y-1/2">
|
|
|
|
|
+ <View className="i-heroicons-user-20-solid text-gray-400 w-5 h-5" />
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <Input
|
|
|
|
|
+ id="username"
|
|
|
|
|
+ className="pl-10"
|
|
|
|
|
+ placeholder="请输入用户名"
|
|
|
|
|
+ value={username}
|
|
|
|
|
+ onInput={handleInput}
|
|
|
|
|
+ />
|
|
|
|
|
+ </View>
|
|
|
|
|
+</View>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 4. 页面布局规范
|
|
|
|
|
+
|
|
|
|
|
+#### 4.1 页面容器
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 主容器
|
|
|
|
|
+<View className="min-h-screen bg-gray-50">
|
|
|
|
|
+ <View className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
|
|
|
+ {/* 页面内容 */}
|
|
|
|
|
+ </View>
|
|
|
|
|
+</View>
|
|
|
|
|
+
|
|
|
|
|
+// 卡片布局
|
|
|
|
|
+<View className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
|
|
|
|
+ {/* 卡片内容 */}
|
|
|
|
|
+</View>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 4.2 响应式断点
|
|
|
|
|
+- `sm`: 640px
|
|
|
|
|
+- `md`: 768px
|
|
|
|
|
+- `lg`: 1024px
|
|
|
|
|
+- `xl`: 1280px
|
|
|
|
|
+- `2xl`: 1536px
|
|
|
|
|
+
|
|
|
|
|
+### 5. 主题配置
|
|
|
|
|
+
|
|
|
|
|
+#### 5.1 颜色系统
|
|
|
|
|
+```css
|
|
|
|
|
+/* 在 app.css 中定义 */
|
|
|
|
|
+:root {
|
|
|
|
|
+ --primary: 59 130 246;
|
|
|
|
|
+ --primary-foreground: 255 255 255;
|
|
|
|
|
+ --secondary: 107 114 128;
|
|
|
|
|
+ --secondary-foreground: 255 255 255;
|
|
|
|
|
+ --accent: 243 244 246;
|
|
|
|
|
+ --accent-foreground: 17 24 39;
|
|
|
|
|
+ --destructive: 239 68 68;
|
|
|
|
|
+ --destructive-foreground: 255 255 255;
|
|
|
|
|
+ --muted: 249 250 251;
|
|
|
|
|
+ --muted-foreground: 107 114 128;
|
|
|
|
|
+ --border: 229 231 235;
|
|
|
|
|
+ --input: 255 255 255;
|
|
|
|
|
+ --ring: 59 130 246;
|
|
|
|
|
+ --background: 255 255 255;
|
|
|
|
|
+ --foreground: 17 24 39;
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 5.2 Tailwind配置
|
|
|
|
|
+```javascript
|
|
|
|
|
+// tailwind.config.js
|
|
|
|
|
+module.exports = {
|
|
|
|
|
+ content: [
|
|
|
|
|
+ './src/**/*.{js,ts,jsx,tsx}',
|
|
|
|
|
+ ],
|
|
|
|
|
+ theme: {
|
|
|
|
|
+ extend: {
|
|
|
|
|
+ colors: {
|
|
|
|
|
+ primary: 'rgb(var(--primary))',
|
|
|
|
|
+ 'primary-foreground': 'rgb(var(--primary-foreground))',
|
|
|
|
|
+ secondary: 'rgb(var(--secondary))',
|
|
|
|
|
+ 'secondary-foreground': 'rgb(var(--secondary-foreground))',
|
|
|
|
|
+ accent: 'rgb(var(--accent))',
|
|
|
|
|
+ 'accent-foreground': 'rgb(var(--accent-foreground))',
|
|
|
|
|
+ destructive: 'rgb(var(--destructive))',
|
|
|
|
|
+ 'destructive-foreground': 'rgb(var(--destructive-foreground))',
|
|
|
|
|
+ muted: 'rgb(var(--muted))',
|
|
|
|
|
+ 'muted-foreground': 'rgb(var(--muted-foreground))',
|
|
|
|
|
+ border: 'rgb(var(--border))',
|
|
|
|
|
+ input: 'rgb(var(--input))',
|
|
|
|
|
+ ring: 'rgb(var(--ring))',
|
|
|
|
|
+ background: 'rgb(var(--background))',
|
|
|
|
|
+ foreground: 'rgb(var(--foreground))',
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ plugins: [
|
|
|
|
|
+ require('@egoist/tailwindcss-icons')({
|
|
|
|
|
+ // 配置Heroicons
|
|
|
|
|
+ collections: {
|
|
|
|
|
+ heroicons: {
|
|
|
|
|
+ solid: true,
|
|
|
|
|
+ outline: true,
|
|
|
|
|
+ mini: true,
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ }),
|
|
|
|
|
+ ],
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 6. 工具函数
|
|
|
|
|
+
|
|
|
|
|
+#### 6.1 类名合并工具
|
|
|
|
|
+```typescript
|
|
|
|
|
+// mini/src/utils/cn.ts
|
|
|
|
|
+import { clsx, type ClassValue } from 'clsx'
|
|
|
|
|
+import { twMerge } from '@weapp-tailwindcss/merge'
|
|
|
|
|
+
|
|
|
|
|
+export function cn(...inputs: ClassValue[]) {
|
|
|
|
|
+ return twMerge(clsx(inputs))
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 6.2 小程序专用类名处理
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 小程序环境下的类名合并
|
|
|
|
|
+import { twMerge } from '@weapp-tailwindcss/merge'
|
|
|
|
|
+
|
|
|
|
|
+// 标准用法(自动处理小程序转义)
|
|
|
|
|
+const classes = twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-[#B91C1C]')
|
|
|
|
|
+// → 'hovercbg-dark-red p-3 bg-_hB91C1C_'
|
|
|
|
|
+
|
|
|
|
|
+// 手动指定版本(如果需要)
|
|
|
|
|
+import { twMerge as twMergeV4 } from '@weapp-tailwindcss/merge/v4'
|
|
|
|
|
+import { twMerge as twMergeV3 } from '@weapp-tailwindcss/merge/v3'
|
|
|
|
|
+
|
|
|
|
|
+// 使用cva进行组件变体管理
|
|
|
|
|
+import { cva } from 'class-variance-authority'
|
|
|
|
|
+
|
|
|
|
|
+const buttonVariants = cva(
|
|
|
|
|
+ 'inline-flex items-center justify-center rounded-md text-sm font-medium',
|
|
|
|
|
+ {
|
|
|
|
|
+ variants: {
|
|
|
|
|
+ variant: {
|
|
|
|
|
+ default: 'bg-blue-500 text-white hover:bg-blue-600',
|
|
|
|
|
+ destructive: 'bg-red-500 text-white hover:bg-red-600',
|
|
|
|
|
+ },
|
|
|
|
|
+ size: {
|
|
|
|
|
+ sm: 'h-8 px-3 text-xs',
|
|
|
|
|
+ lg: 'h-12 px-6 text-base',
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ }
|
|
|
|
|
+)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 7. 最佳实践
|
|
|
|
|
+
|
|
|
|
|
+#### 7.1 状态管理
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 使用React Hook进行状态管理
|
|
|
|
|
+const [loading, setLoading] = useState(false)
|
|
|
|
|
+const [data, setData] = useState<User[]>([])
|
|
|
|
|
+
|
|
|
|
|
+// 加载状态显示
|
|
|
|
|
+{loading ? (
|
|
|
|
|
+ <View className="flex justify-center py-8">
|
|
|
|
|
+ <View className="i-heroicons-arrow-path-20-solid animate-spin w-8 h-8 text-blue-500" />
|
|
|
|
|
+ </View>
|
|
|
|
|
+) : (
|
|
|
|
|
+ <View className="grid grid-cols-1 gap-4">
|
|
|
|
|
+ {data.map(item => <Card key={item.id} {...item} />)}
|
|
|
|
|
+ </View>
|
|
|
|
|
+)}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 7.2 错误处理
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 错误状态展示
|
|
|
|
|
+<View className="text-center py-8">
|
|
|
|
|
+ <View className="i-heroicons-exclamation-triangle-20-solid w-12 h-12 text-red-500 mx-auto mb-4" />
|
|
|
|
|
+ <Text className="text-gray-600">加载失败,请稍后重试</Text>
|
|
|
|
|
+ <Button variant="outline" size="sm" onClick={retry} className="mt-4">
|
|
|
|
|
+ 重新加载
|
|
|
|
|
+ </Button>
|
|
|
|
|
+</View>
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 8. 性能优化
|
|
|
|
|
+
|
|
|
|
|
+#### 8.1 样式优化
|
|
|
|
|
+- 使用Tailwind的JIT模式,只生成用到的类名
|
|
|
|
|
+- 避免内联样式,全部使用类名
|
|
|
|
|
+- 合理使用`@apply`提取重复样式
|
|
|
|
|
+
|
|
|
|
|
+#### 8.2 图标优化
|
|
|
|
|
+- 使用CSS图标而非图片图标
|
|
|
|
|
+- 图标按需加载,不使用的图标不会被打包
|
|
|
|
|
+- 合理使用图标大小,避免过大图标
|
|
|
|
|
+
|
|
|
|
|
+### 9. 调试工具
|
|
|
|
|
+
|
|
|
|
|
+#### 9.1 开发调试
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 添加调试样式类
|
|
|
|
|
+<View className="border border-red-500 debug">
|
|
|
|
|
+ <Text>调试内容</Text>
|
|
|
|
|
+</View>
|
|
|
|
|
+
|
|
|
|
|
+// 使用Tailwind的调试工具
|
|
|
|
|
+// 在开发环境中添加
|
|
|
|
|
+// <View className="outline outline-1 outline-red-500" />
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 10. tailwind-merge使用规范
|
|
|
|
|
+
|
|
|
|
|
+#### 10.1 基本用法
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 单类名合并
|
|
|
|
|
+const result = twMerge('px-2 py-1 bg-red hover:bg-dark-red', 'p-3 bg-[#B91C1C]')
|
|
|
|
|
+// → 'hovercbg-dark-red p-3 bg-_hB91C1C_'
|
|
|
|
|
+
|
|
|
|
|
+// 处理冲突类名
|
|
|
|
|
+twMerge('px-4', 'px-2') // → 'px-2'
|
|
|
|
|
+twMerge('text-red-500', 'text-blue-500') // → 'text-blue-500'
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 10.2 条件类名处理
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 使用cn工具函数处理条件类名
|
|
|
|
|
+import { cn } from '@/utils/cn'
|
|
|
|
|
+
|
|
|
|
|
+const Button = ({ variant, size, disabled, className }) => {
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Button
|
|
|
|
|
+ className={cn(
|
|
|
|
|
+ 'inline-flex items-center justify-center rounded-md',
|
|
|
|
|
+ variant === 'primary' && 'bg-blue-500 text-white',
|
|
|
|
|
+ variant === 'secondary' && 'bg-gray-200 text-gray-800',
|
|
|
|
|
+ size === 'sm' && 'px-3 py-1 text-sm',
|
|
|
|
|
+ size === 'lg' && 'px-6 py-3 text-lg',
|
|
|
|
|
+ disabled && 'opacity-50 cursor-not-allowed',
|
|
|
|
|
+ className // 允许外部覆盖
|
|
|
|
|
+ )}
|
|
|
|
|
+ >
|
|
|
|
|
+ 按钮
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 10.3 小程序特殊处理
|
|
|
|
|
+```typescript
|
|
|
|
|
+// 跨端使用
|
|
|
|
|
+import { create } from '@weapp-tailwindcss/merge'
|
|
|
|
|
+
|
|
|
|
|
+const { twMerge } = create({
|
|
|
|
|
+ // 在当前环境为小程序时启用转义
|
|
|
|
|
+ disableEscape: true
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+// 版本选择
|
|
|
|
|
+import { twMerge as twMergeV4 } from '@weapp-tailwindcss/merge/v4' // Tailwind v4
|
|
|
|
|
+import { twMerge as twMergeV3 } from '@weapp-tailwindcss/merge/v3' // Tailwind v3
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 注意事项
|
|
|
|
|
+
|
|
|
|
|
+1. **兼容性**:确保所有类名在小程序环境中有效
|
|
|
|
|
+2. **性能**:避免过度嵌套和复杂选择器
|
|
|
|
|
+3. **可维护性**:保持组件结构清晰,样式统一
|
|
|
|
|
+4. **可读性**:合理使用空格和换行,提高代码可读性
|
|
|
|
|
+5. **tailwind-merge**:始终使用twMerge或cn工具函数处理动态类名,避免类名冲突
|
|
|
|
|
+6. **版本兼容**:根据Tailwind CSS版本选择正确的tailwind-merge版本
|