自定义组件

了解如何使用 Tailwind Variants API 来自定义 Nuxt UI 组件,以实现高级、灵活和可维护的样式。

Tailwind Variants

Nuxt UI 组件使用Tailwind VariantsAPI 进行样式设置,该 API 提供了一种创建变体和管理组件样式的强大方法。

插槽

组件可以有多个 slots,每个 slot 代表组件内一个不同的 HTML 元素或区域。这些 slots 允许灵活地插入内容和进行样式设置。

以具有多个 slots 的 Card 组件为例

export default {
  slots: {
    root: 'bg-default ring ring-default divide-y divide-default rounded-lg',
    header: 'p-4 sm:px-6',
    body: 'p-4 sm:p-6',
    footer: 'p-4 sm:px-6'
  }
}

有些组件没有 slots,它们只由一个根元素组成。在这种情况下,主题仅定义了 base slot,例如 Container 组件

export default {
  base: 'max-w-(--ui-container) mx-auto px-4 sm:px-6 lg:px-8'
}
没有 slots 的组件没有ui 属性,只有class 属性可用于覆盖样式。

变体 (Variants)

组件支持 variants,这允许您根据组件的 props 动态调整不同 slots 的样式。

例如,Avatar 组件使用 size 变体来控制其外观

src/theme/avatar.ts
export default {
  slots: {
    root: 'inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle bg-elevated',
    image: 'h-full w-full rounded-[inherit] object-cover'
  },
  variants: {
    size: {
      sm: {
        root: 'size-7 text-sm'
      },
      md: {
        root: 'size-8 text-base'
      },
      lg: {
        root: 'size-9 text-lg'
      }
    }
  },
  defaultVariants: {
    size: 'md'
  }
}

这样,size prop 将把相应的样式应用于 root slot

<template>
  <UAvatar src="https://github.com/nuxt.png" size="lg" />
</template>

默认变体 (Default Variants)

defaultVariants 属性设置每个变体的默认值,当没有传递 prop 时。

例如,Avatar 组件的默认大小设置为 md

src/theme/avatar.ts
export default {
  slots: {
    root: 'inline-flex items-center justify-center shrink-0 select-none overflow-hidden rounded-full align-middle bg-elevated',
    image: 'h-full w-full rounded-[inherit] object-cover'
  },
  variants: {
    size: {
      sm: {
        root: 'size-7 text-sm'
      },
      md: {
        root: 'size-8 text-base'
      },
      lg: {
        root: 'size-9 text-lg'
      }
    }
  },
  defaultVariants: {
    size: 'md'
  }
}
您可以在 nuxt.config.ts 中使用 theme.defaultVariants 选项,一次性覆盖所有组件的 sizecolor 的默认值。
您可以在 vite.config.ts 中使用 theme.defaultVariants 选项,一次性覆盖所有组件的 sizecolor 的默认值。

组合变体 (Compound Variants)

某些组件使用 compoundVariants 属性,在多个变体条件同时满足时应用类。

例如,Button 组件使用 compoundVariants 属性来为特定的 colorvariant 组合应用类

src/theme/button.ts
import type { ModuleOptions } from '../module'

export default (options: Required<ModuleOptions>) => ({
  slots: {
    base: ['rounded-md font-medium inline-flex items-center disabled:cursor-not-allowed aria-disabled:cursor-not-allowed disabled:opacity-75 aria-disabled:opacity-75', options.theme.transitions && 'transition-colors']
  },
  variants: {
    color: {
      ...Object.fromEntries((options.theme.colors || []).map((color: string) => [color, ''])),
      neutral: ''
    },
    variant: {
      solid: '',
      outline: '',
      soft: '',
      subtle: '',
      ghost: '',
      link: ''
    }
  },
  compoundVariants: [
    ...(options.theme.colors || []).map((color: string) => ({
      color,
      variant: 'outline',
      class: `ring ring-inset ring-${color}/50 text-${color} hover:bg-${color}/10 active:bg-${color}/10 disabled:bg-transparent aria-disabled:bg-transparent dark:disabled:bg-transparent dark:aria-disabled:bg-transparent focus:outline-none focus-visible:ring-2 focus-visible:ring-${color}`
    })),
    {
      color: 'neutral',
      variant: 'outline',
      class: 'ring ring-inset ring-accented text-default bg-default hover:bg-elevated active:bg-elevated disabled:bg-default aria-disabled:bg-default focus:outline-none focus-visible:ring-2 focus-visible:ring-inverted'
    }
  ],
  defaultVariants: {
    color: 'primary',
    variant: 'solid'
  }
})

自定义主题

您有多种方式来自定义 Nuxt UI 组件的外观,您可以一次性为所有组件进行自定义,也可以按组件进行自定义。

Tailwind Variants 在后台使用tailwind-merge来合并类,因此您不必担心类冲突。
您可以通过两种方式探索每个组件的主题
  • 查看每个组件文档中的 Theme 部分。
  • 直接在 GitHub 仓库中浏览源代码,地址为:src/theme.

全局配置

您可以通过使用与主题对象完全相同的结构,在 app.config.ts 中全局覆盖组件的主题。

您可以通过使用与主题对象完全相同的结构,在 vite.config.ts 中全局覆盖组件的主题。

您可以自定义slots, variants, compoundVariantsdefaultVariants组件的,以更改组件的默认主题。

app.config.ts
export default defineAppConfig({
  ui: {
    button: {
      slots: {
        base: 'font-bold'
      },
      variants: {
        size: {
          md: {
            leadingIcon: 'size-4'
          }
        }
      },
      compoundVariants: [{
        color: 'neutral',
        variant: 'outline',
        class: 'ring-default hover:bg-accented'
      }],
      defaultVariants: {
        color: 'neutral',
        variant: 'outline'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        button: {
          slots: {
            base: 'font-bold'
          },
          variants: {
            size: {
              md: {
                leadingIcon: 'size-4'
              }
            }
          },
          compoundVariants: [{
            color: 'neutral',
            variant: 'outline',
            class: 'ring-default hover:bg-accented'
          }],
          defaultVariants: {
            color: 'neutral',
            variant: 'outline'
          }
        }
      }
    })
  ]
})
在此示例中,font-bold 覆盖了所有按钮上的 font-medium;当 size="md" 时,size-4 覆盖了前导图标上的 size-5 类;当 color="neutral"variant="outline" 时,ring-default hover:bg-accented 覆盖了 ring-accented hover:bg-elevated。按钮现在默认为 color="neutral"variant="outline"

ui 属性

您还可以使用 ui prop 来覆盖组件的 slots。这优先于全局配置和已解析的 variants

<template>
  <UButton
    trailing-icon="i-lucide-chevron-right"
    size="md"
    color="neutral"
    variant="outline"
    :ui="{
      trailingIcon: 'rotate-90 size-3'
    }"
  >
    Button
  </UButton>
</template>
在此示例中,trailingIcon slot 被覆盖为 size-3,即使 md size 变体会为其应用 size-5 类。

class 属性

class prop 允许您覆盖 rootbase slot 的类。这优先于全局配置和已解析的 variants

<template>
  <UButton class="font-bold rounded-full">Button</UButton>
</template>
在此示例中,font-bold 类将覆盖此按钮上默认的 font-medium 类。